stringcase/
kebab_case.rs

1// Copyright (C) 2024-2025 Takayuki Sato. All Rights Reserved.
2// This program is free software under MIT License.
3// See the file LICENSE in this distribution for more details.
4
5use crate::options::Options;
6
7/// Converts the input string to kebab case with the specified options.
8///
9/// ```rust
10///     let opts = stringcase::Options{
11///       separate_before_non_alphabets: true,
12///       separate_after_non_alphabets: true,
13///       separators: "",
14///       keep: "",
15///     };
16///     let kebab = stringcase::kebab_case_with_options("fooBar123Baz", &opts);
17///     assert_eq!(kebab, "foo-bar-123-baz");
18/// ```
19pub fn kebab_case_with_options(input: &str, opts: &Options) -> String {
20    let mut result = String::with_capacity(input.len() + input.len() / 2);
21    // .len returns byte count but ok in this case!
22
23    #[derive(PartialEq)]
24    enum ChIs {
25        FirstOfStr,
26        NextOfUpper,
27        NextOfContdUpper,
28        NextOfSepMark,
29        NextOfKeptMark,
30        Other,
31    }
32
33    let mut flag = ChIs::FirstOfStr;
34
35    for ch in input.chars() {
36        if ch.is_ascii_uppercase() {
37            if flag == ChIs::FirstOfStr {
38                result.push(ch.to_ascii_lowercase());
39                flag = ChIs::NextOfUpper;
40            } else if flag == ChIs::NextOfUpper
41                || flag == ChIs::NextOfContdUpper
42                || (!opts.separate_after_non_alphabets && flag == ChIs::NextOfKeptMark)
43            {
44                result.push(ch.to_ascii_lowercase());
45                flag = ChIs::NextOfContdUpper;
46            } else {
47                result.push('-');
48                result.push(ch.to_ascii_lowercase());
49                flag = ChIs::NextOfUpper;
50            }
51        } else if ch.is_ascii_lowercase() {
52            if flag == ChIs::NextOfContdUpper {
53                if let Some(prev) = result.pop() {
54                    result.push('-');
55                    result.push(prev);
56                    result.push(ch);
57                }
58            } else if flag == ChIs::NextOfSepMark
59                || (opts.separate_after_non_alphabets && flag == ChIs::NextOfKeptMark)
60            {
61                result.push('-');
62                result.push(ch);
63            } else {
64                result.push(ch);
65            }
66            flag = ChIs::Other;
67        } else {
68            let mut is_kept_char = false;
69            if ch.is_ascii_digit() {
70                is_kept_char = true;
71            } else if !opts.separators.is_empty() {
72                if !opts.separators.contains(ch) {
73                    is_kept_char = true;
74                }
75            } else if !opts.keep.is_empty() {
76                if opts.keep.contains(ch) {
77                    is_kept_char = true;
78                }
79            }
80
81            if is_kept_char {
82                if opts.separate_before_non_alphabets {
83                    if flag == ChIs::FirstOfStr || flag == ChIs::NextOfKeptMark {
84                        result.push(ch);
85                    } else {
86                        result.push('-');
87                        result.push(ch);
88                    }
89                } else {
90                    if flag != ChIs::NextOfSepMark {
91                        result.push(ch);
92                    } else {
93                        result.push('-');
94                        result.push(ch);
95                    }
96                }
97                flag = ChIs::NextOfKeptMark;
98            } else {
99                if flag != ChIs::FirstOfStr {
100                    flag = ChIs::NextOfSepMark;
101                }
102            }
103        }
104    }
105
106    result
107}
108
109/// Converts the input string to kebab case.
110///
111/// It treats the end of a sequence of non-alphabetical characters as a word boundary, but not
112/// the beginning.
113///
114/// ```rust
115///     let kebab = stringcase::kebab_case("fooBar123Baz");
116///     assert_eq!(kebab, "foo-bar123-baz");
117/// ```
118pub fn kebab_case(input: &str) -> String {
119    let opts = Options {
120        separate_before_non_alphabets: false,
121        separate_after_non_alphabets: true,
122        separators: "",
123        keep: "",
124    };
125    kebab_case_with_options(input, &opts)
126}
127
128/// Converts the input string to kebab case with the specified separator characters.
129#[deprecated(since = "0.4.0", note = "Should use kebab_case_with_options instead")]
130pub fn kebab_case_with_sep(input: &str, seps: &str) -> String {
131    let opts = Options {
132        separate_before_non_alphabets: false,
133        separate_after_non_alphabets: true,
134        separators: seps,
135        keep: "",
136    };
137    kebab_case_with_options(input, &opts)
138}
139
140/// Converts the input string to kebab case with the specified characters to be kept.
141#[deprecated(since = "0.4.0", note = "Should use kebab_case_with_options instead")]
142pub fn kebab_case_with_keep(input: &str, kept: &str) -> String {
143    let opts = Options {
144        separate_before_non_alphabets: false,
145        separate_after_non_alphabets: true,
146        separators: "",
147        keep: kept,
148    };
149    kebab_case_with_options(input, &opts)
150}
151
152/// Converts the input string to kebab case.
153///
154/// It treats the beginning and the end of a sequence of non-alphabetical characters as a word
155/// boundary.
156#[deprecated(since = "0.4.0", note = "Should use kebab_case_with_options instead")]
157pub fn kebab_case_with_nums_as_word(input: &str) -> String {
158    let opts = Options {
159        separate_before_non_alphabets: true,
160        separate_after_non_alphabets: true,
161        separators: "",
162        keep: "",
163    };
164    kebab_case_with_options(input, &opts)
165}
166
167#[cfg(test)]
168mod tests_of_kebab_case {
169    use super::*;
170
171    #[test]
172    fn convert_camel_case() {
173        let result = kebab_case("abcDefGHIjk");
174        assert_eq!(result, "abc-def-gh-ijk");
175    }
176
177    #[test]
178    fn convert_pascal_case() {
179        let result = kebab_case("AbcDefGHIjk");
180        assert_eq!(result, "abc-def-gh-ijk");
181    }
182
183    #[test]
184    fn convert_snake_case() {
185        let result = kebab_case("abc_def_ghi");
186        assert_eq!(result, "abc-def-ghi");
187    }
188
189    #[test]
190    fn convert_kebab_case() {
191        let result = kebab_case("abc-def-ghi");
192        assert_eq!(result, "abc-def-ghi");
193    }
194
195    #[test]
196    fn convert_train_case() {
197        let result = kebab_case("Abc-Def-Ghi");
198        assert_eq!(result, "abc-def-ghi");
199    }
200
201    #[test]
202    fn convert_macro_case() {
203        let result = kebab_case("ABC_DEF_GHI");
204        assert_eq!(result, "abc-def-ghi");
205    }
206
207    #[test]
208    fn convert_cobol_case() {
209        let result = kebab_case("ABC-DEF-GHI");
210        assert_eq!(result, "abc-def-ghi");
211    }
212
213    #[test]
214    fn convert_with_keeping_digits() {
215        let result = kebab_case("abc123-456defG89HIJklMN12");
216        assert_eq!(result, "abc123-456-def-g89-hi-jkl-mn12");
217    }
218
219    #[test]
220    fn convert_with_symbols_as_separators() {
221        let result = kebab_case(":.abc~!@def#$ghi%&jk(lm)no/?");
222        assert_eq!(result, "abc-def-ghi-jk-lm-no");
223    }
224
225    #[test]
226    fn convert_when_starting_with_digit() {
227        let result = kebab_case("123abc456def");
228        assert_eq!(result, "123-abc456-def");
229
230        let result = kebab_case("123ABC456DEF");
231        assert_eq!(result, "123-abc456-def");
232
233        let result = kebab_case("123Abc456Def");
234        assert_eq!(result, "123-abc456-def");
235    }
236
237    #[test]
238    fn convert_empty_string() {
239        let result = kebab_case("");
240        assert_eq!(result, "");
241    }
242}
243
244#[cfg(test)]
245mod tests_of_cobol_case_with_options {
246    use super::*;
247
248    mod non_alphabets_as_head_of_a_word {
249        use super::*;
250
251        #[test]
252        fn convert_camel_case() {
253            let opts = Options {
254                separate_before_non_alphabets: true,
255                separate_after_non_alphabets: false,
256                separators: "",
257                keep: "",
258            };
259
260            let result = kebab_case_with_options("abcDefGHIjk", &opts);
261            assert_eq!(result, "abc-def-gh-ijk");
262        }
263
264        #[test]
265        fn convert_pascal_case() {
266            let opts = Options {
267                separate_before_non_alphabets: true,
268                separate_after_non_alphabets: false,
269                separators: "",
270                keep: "",
271            };
272
273            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
274            assert_eq!(result, "abc-def-gh-ijk");
275        }
276
277        #[test]
278        fn convert_snake_case() {
279            let opts = Options {
280                separate_before_non_alphabets: true,
281                separate_after_non_alphabets: false,
282                separators: "",
283                keep: "",
284            };
285
286            let result = kebab_case_with_options("abc_def_ghi", &opts);
287            assert_eq!(result, "abc-def-ghi");
288        }
289
290        #[test]
291        fn convert_kebab_case() {
292            let opts = Options {
293                separate_before_non_alphabets: true,
294                separate_after_non_alphabets: false,
295                separators: "",
296                keep: "",
297            };
298
299            let result = kebab_case_with_options("abc-def-ghi", &opts);
300            assert_eq!(result, "abc-def-ghi");
301        }
302
303        #[test]
304        fn convert_train_case() {
305            let opts = Options {
306                separate_before_non_alphabets: true,
307                separate_after_non_alphabets: false,
308                separators: "",
309                keep: "",
310            };
311
312            let result = kebab_case_with_options("Abc-Def-Ghi", &opts);
313            assert_eq!(result, "abc-def-ghi");
314        }
315
316        #[test]
317        fn convert_macro_case() {
318            let opts = Options {
319                separate_before_non_alphabets: true,
320                separate_after_non_alphabets: false,
321                separators: "",
322                keep: "",
323            };
324
325            let result = kebab_case_with_options("ABC_DEF_GHI", &opts);
326            assert_eq!(result, "abc-def-ghi");
327        }
328
329        #[test]
330        fn convert_cobol_case() {
331            let opts = Options {
332                separate_before_non_alphabets: true,
333                separate_after_non_alphabets: false,
334                separators: "",
335                keep: "",
336            };
337
338            let result = kebab_case_with_options("ABC-DEF-GHI", &opts);
339            assert_eq!(result, "abc-def-ghi");
340        }
341
342        #[test]
343        fn convert_with_keeping_digits() {
344            let opts = Options {
345                separate_before_non_alphabets: true,
346                separate_after_non_alphabets: false,
347                separators: "",
348                keep: "",
349            };
350
351            let result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
352            assert_eq!(result, "abc-123-456def-g-89hi-jkl-mn-12");
353        }
354
355        #[test]
356        fn convert_with_symbols_as_separators() {
357            let opts = Options {
358                separate_before_non_alphabets: true,
359                separate_after_non_alphabets: false,
360                separators: "",
361                keep: "",
362            };
363
364            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
365            assert_eq!(result, "abc-def-ghi-jk-lm-no");
366        }
367
368        #[test]
369        fn convert_when_starting_with_digit() {
370            let opts = Options {
371                separate_before_non_alphabets: true,
372                separate_after_non_alphabets: false,
373                separators: "",
374                keep: "",
375            };
376
377            let result = kebab_case_with_options("123abc456def", &opts);
378            assert_eq!(result, "123abc-456def");
379
380            let result = kebab_case_with_options("123ABC456DEF", &opts);
381            assert_eq!(result, "123abc-456def");
382
383            let result = kebab_case_with_options("123Abc456Def", &opts);
384            assert_eq!(result, "123-abc-456-def");
385        }
386
387        #[test]
388        fn convert_empty_string() {
389            let opts = Options {
390                separate_before_non_alphabets: true,
391                separate_after_non_alphabets: false,
392                separators: "",
393                keep: "",
394            };
395
396            let result = kebab_case_with_options("", &opts);
397            assert_eq!(result, "");
398        }
399    }
400
401    mod non_alphabets_as_tail_of_a_word {
402        use super::*;
403
404        #[test]
405        fn convert_camel_case() {
406            let opts = Options {
407                separate_before_non_alphabets: false,
408                separate_after_non_alphabets: true,
409                separators: "",
410                keep: "",
411            };
412
413            let result = kebab_case_with_options("abcDefGHIjk", &opts);
414            assert_eq!(result, "abc-def-gh-ijk");
415        }
416
417        #[test]
418        fn convert_pascal_case() {
419            let opts = Options {
420                separate_before_non_alphabets: false,
421                separate_after_non_alphabets: true,
422                separators: "",
423                keep: "",
424            };
425
426            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
427            assert_eq!(result, "abc-def-gh-ijk");
428        }
429
430        #[test]
431        fn convert_snake_case() {
432            let opts = Options {
433                separate_before_non_alphabets: false,
434                separate_after_non_alphabets: true,
435                separators: "",
436                keep: "",
437            };
438
439            let result = kebab_case_with_options("abc_def_ghi", &opts);
440            assert_eq!(result, "abc-def-ghi");
441        }
442
443        #[test]
444        fn convert_kebab_case() {
445            let opts = Options {
446                separate_before_non_alphabets: false,
447                separate_after_non_alphabets: true,
448                separators: "",
449                keep: "",
450            };
451
452            let result = kebab_case_with_options("abc-def-ghi", &opts);
453            assert_eq!(result, "abc-def-ghi");
454        }
455
456        #[test]
457        fn convert_train_case() {
458            let opts = Options {
459                separate_before_non_alphabets: false,
460                separate_after_non_alphabets: true,
461                separators: "",
462                keep: "",
463            };
464
465            let result = kebab_case_with_options("Abc-Def-Ghi", &opts);
466            assert_eq!(result, "abc-def-ghi");
467        }
468
469        #[test]
470        fn convert_macro_case() {
471            let opts = Options {
472                separate_before_non_alphabets: false,
473                separate_after_non_alphabets: true,
474                separators: "",
475                keep: "",
476            };
477
478            let result = kebab_case_with_options("ABC_DEF_GHI", &opts);
479            assert_eq!(result, "abc-def-ghi");
480        }
481
482        #[test]
483        fn convert_cobol_case() {
484            let opts = Options {
485                separate_before_non_alphabets: false,
486                separate_after_non_alphabets: true,
487                separators: "",
488                keep: "",
489            };
490
491            let result = kebab_case_with_options("ABC-DEF-GHI", &opts);
492            assert_eq!(result, "abc-def-ghi");
493        }
494
495        #[test]
496        fn convert_with_keeping_digits() {
497            let opts = Options {
498                separate_before_non_alphabets: false,
499                separate_after_non_alphabets: true,
500                separators: "",
501                keep: "",
502            };
503
504            let result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
505            assert_eq!(result, "abc123-456-def-g89-hi-jkl-mn12");
506        }
507
508        #[test]
509        fn convert_with_symbols_as_separators() {
510            let opts = Options {
511                separate_before_non_alphabets: false,
512                separate_after_non_alphabets: true,
513                separators: "",
514                keep: "",
515            };
516
517            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
518            assert_eq!(result, "abc-def-ghi-jk-lm-no");
519        }
520
521        #[test]
522        fn convert_when_starting_with_digit() {
523            let opts = Options {
524                separate_before_non_alphabets: false,
525                separate_after_non_alphabets: true,
526                separators: "",
527                keep: "",
528            };
529
530            let result = kebab_case_with_options("123abc456def", &opts);
531            assert_eq!(result, "123-abc456-def");
532
533            let result = kebab_case_with_options("123ABC456DEF", &opts);
534            assert_eq!(result, "123-abc456-def");
535
536            let result = kebab_case_with_options("123Abc456Def", &opts);
537            assert_eq!(result, "123-abc456-def");
538        }
539
540        #[test]
541        fn convert_empty_string() {
542            let opts = Options {
543                separate_before_non_alphabets: false,
544                separate_after_non_alphabets: true,
545                separators: "",
546                keep: "",
547            };
548
549            let result = kebab_case_with_options("", &opts);
550            assert_eq!(result, "");
551        }
552    }
553
554    mod non_alphabets_as_a_word {
555        use super::*;
556
557        #[test]
558        fn convert_camel_case() {
559            let opts = Options {
560                separate_before_non_alphabets: true,
561                separate_after_non_alphabets: true,
562                separators: "",
563                keep: "",
564            };
565
566            let result = kebab_case_with_options("abcDefGHIjk", &opts);
567            assert_eq!(result, "abc-def-gh-ijk");
568        }
569
570        #[test]
571        fn convert_pascal_case() {
572            let opts = Options {
573                separate_before_non_alphabets: true,
574                separate_after_non_alphabets: true,
575                separators: "",
576                keep: "",
577            };
578
579            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
580            assert_eq!(result, "abc-def-gh-ijk");
581        }
582
583        #[test]
584        fn convert_snake_case() {
585            let opts = Options {
586                separate_before_non_alphabets: true,
587                separate_after_non_alphabets: true,
588                separators: "",
589                keep: "",
590            };
591
592            let result = kebab_case_with_options("abc_def_ghi", &opts);
593            assert_eq!(result, "abc-def-ghi");
594        }
595
596        #[test]
597        fn convert_kebab_case() {
598            let opts = Options {
599                separate_before_non_alphabets: true,
600                separate_after_non_alphabets: true,
601                separators: "",
602                keep: "",
603            };
604
605            let result = kebab_case_with_options("abc-def-ghi", &opts);
606            assert_eq!(result, "abc-def-ghi");
607        }
608
609        #[test]
610        fn convert_train_case() {
611            let opts = Options {
612                separate_before_non_alphabets: true,
613                separate_after_non_alphabets: true,
614                separators: "",
615                keep: "",
616            };
617
618            let result = kebab_case_with_options("Abc-Def-Ghi", &opts);
619            assert_eq!(result, "abc-def-ghi");
620        }
621
622        #[test]
623        fn convert_macro_case() {
624            let opts = Options {
625                separate_before_non_alphabets: true,
626                separate_after_non_alphabets: true,
627                separators: "",
628                keep: "",
629            };
630
631            let result = kebab_case_with_options("ABC_DEF_GHI", &opts);
632            assert_eq!(result, "abc-def-ghi");
633        }
634
635        #[test]
636        fn convert_cobol_case() {
637            let opts = Options {
638                separate_before_non_alphabets: true,
639                separate_after_non_alphabets: true,
640                separators: "",
641                keep: "",
642            };
643
644            let result = kebab_case_with_options("ABC-DEF-GHI", &opts);
645            assert_eq!(result, "abc-def-ghi");
646        }
647
648        #[test]
649        fn convert_with_keeping_digits() {
650            let opts = Options {
651                separate_before_non_alphabets: true,
652                separate_after_non_alphabets: true,
653                separators: "",
654                keep: "",
655            };
656
657            let result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
658            assert_eq!(result, "abc-123-456-def-g-89-hi-jkl-mn-12");
659        }
660
661        #[test]
662        fn convert_with_symbols_as_separators() {
663            let opts = Options {
664                separate_before_non_alphabets: true,
665                separate_after_non_alphabets: true,
666                separators: "",
667                keep: "",
668            };
669
670            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
671            assert_eq!(result, "abc-def-ghi-jk-lm-no");
672        }
673
674        #[test]
675        fn convert_when_starting_with_digit() {
676            let opts = Options {
677                separate_before_non_alphabets: true,
678                separate_after_non_alphabets: true,
679                separators: "",
680                keep: "",
681            };
682
683            let result = kebab_case_with_options("123abc456def", &opts);
684            assert_eq!(result, "123-abc-456-def");
685
686            let result = kebab_case_with_options("123ABC456DEF", &opts);
687            assert_eq!(result, "123-abc-456-def");
688
689            let result = kebab_case_with_options("123Abc456Def", &opts);
690            assert_eq!(result, "123-abc-456-def");
691        }
692
693        #[test]
694        fn convert_empty_string() {
695            let opts = Options {
696                separate_before_non_alphabets: true,
697                separate_after_non_alphabets: true,
698                separators: "",
699                keep: "",
700            };
701
702            let result = kebab_case_with_options("", &opts);
703            assert_eq!(result, "");
704        }
705    }
706
707    mod non_alphabets_as_part_of_a_word {
708        use super::*;
709
710        #[test]
711        fn convert_camel_case() {
712            let opts = Options {
713                separate_before_non_alphabets: false,
714                separate_after_non_alphabets: false,
715                separators: "",
716                keep: "",
717            };
718
719            let result = kebab_case_with_options("abcDefGHIjk", &opts);
720            assert_eq!(result, "abc-def-gh-ijk");
721        }
722
723        #[test]
724        fn convert_pascal_case() {
725            let opts = Options {
726                separate_before_non_alphabets: false,
727                separate_after_non_alphabets: false,
728                separators: "",
729                keep: "",
730            };
731
732            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
733            assert_eq!(result, "abc-def-gh-ijk");
734        }
735
736        #[test]
737        fn convert_snake_case() {
738            let opts = Options {
739                separate_before_non_alphabets: false,
740                separate_after_non_alphabets: false,
741                separators: "",
742                keep: "",
743            };
744
745            let result = kebab_case_with_options("abc_def_ghi", &opts);
746            assert_eq!(result, "abc-def-ghi");
747        }
748
749        #[test]
750        fn convert_kebab_case() {
751            let opts = Options {
752                separate_before_non_alphabets: false,
753                separate_after_non_alphabets: false,
754                separators: "",
755                keep: "",
756            };
757
758            let result = kebab_case_with_options("abc-def-ghi", &opts);
759            assert_eq!(result, "abc-def-ghi");
760        }
761
762        #[test]
763        fn convert_train_case() {
764            let opts = Options {
765                separate_before_non_alphabets: false,
766                separate_after_non_alphabets: false,
767                separators: "",
768                keep: "",
769            };
770
771            let result = kebab_case_with_options("Abc-Def-Ghi", &opts);
772            assert_eq!(result, "abc-def-ghi");
773        }
774
775        #[test]
776        fn convert_macro_case() {
777            let opts = Options {
778                separate_before_non_alphabets: false,
779                separate_after_non_alphabets: false,
780                separators: "",
781                keep: "",
782            };
783
784            let result = kebab_case_with_options("ABC_DEF_GHI", &opts);
785            assert_eq!(result, "abc-def-ghi");
786        }
787
788        #[test]
789        fn convert_cobol_case() {
790            let opts = Options {
791                separate_before_non_alphabets: false,
792                separate_after_non_alphabets: false,
793                separators: "",
794                keep: "",
795            };
796
797            let result = kebab_case_with_options("ABC-DEF-GHI", &opts);
798            assert_eq!(result, "abc-def-ghi");
799        }
800
801        #[test]
802        fn convert_with_keeping_digits() {
803            let opts = Options {
804                separate_before_non_alphabets: false,
805                separate_after_non_alphabets: false,
806                separators: "",
807                keep: "",
808            };
809
810            let result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
811            assert_eq!(result, "abc123-456def-g89hi-jkl-mn12");
812        }
813
814        #[test]
815        fn convert_with_symbols_as_separators() {
816            let opts = Options {
817                separate_before_non_alphabets: false,
818                separate_after_non_alphabets: false,
819                separators: "",
820                keep: "",
821            };
822
823            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
824            assert_eq!(result, "abc-def-ghi-jk-lm-no");
825        }
826
827        #[test]
828        fn convert_when_starting_with_digit() {
829            let opts = Options {
830                separate_before_non_alphabets: false,
831                separate_after_non_alphabets: false,
832                separators: "",
833                keep: "",
834            };
835
836            let result = kebab_case_with_options("123abc456def", &opts);
837            assert_eq!(result, "123abc456def");
838
839            let result = kebab_case_with_options("123ABC456DEF", &opts);
840            assert_eq!(result, "123abc456def");
841
842            let result = kebab_case_with_options("123Abc456Def", &opts);
843            assert_eq!(result, "123-abc456-def");
844        }
845
846        #[test]
847        fn convert_empty_string() {
848            let opts = Options {
849                separate_before_non_alphabets: false,
850                separate_after_non_alphabets: false,
851                separators: "",
852                keep: "",
853            };
854
855            let result = kebab_case_with_options("", &opts);
856            assert_eq!(result, "");
857        }
858    }
859
860    mod non_alphabets_as_head_of_a_word_with_separators {
861        use super::*;
862
863        #[test]
864        fn convert_camel_case() {
865            let opts = Options {
866                separate_before_non_alphabets: true,
867                separate_after_non_alphabets: false,
868                separators: "-_",
869                keep: "",
870            };
871
872            let result = kebab_case_with_options("abcDefGHIjk", &opts);
873            assert_eq!(result, "abc-def-gh-ijk");
874        }
875
876        #[test]
877        fn convert_pascal_case() {
878            let opts = Options {
879                separate_before_non_alphabets: true,
880                separate_after_non_alphabets: false,
881                separators: "-_",
882                keep: "",
883            };
884
885            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
886            assert_eq!(result, "abc-def-gh-ijk");
887        }
888
889        #[test]
890        fn convert_snake_case() {
891            let mut opts = Options {
892                separate_before_non_alphabets: true,
893                separate_after_non_alphabets: false,
894                separators: "_",
895                keep: "",
896            };
897
898            let mut result = kebab_case_with_options("abc_def_ghi", &opts);
899            assert_eq!(result, "abc-def-ghi");
900
901            opts.separators = "-";
902            result = kebab_case_with_options("abc_def_ghi", &opts);
903            assert_eq!(result, "abc-_def-_ghi");
904        }
905
906        #[test]
907        fn convert_kebab_case() {
908            let mut opts = Options {
909                separate_before_non_alphabets: true,
910                separate_after_non_alphabets: false,
911                separators: "-",
912                keep: "",
913            };
914
915            let mut result = kebab_case_with_options("abc-def-ghi", &opts);
916            assert_eq!(result, "abc-def-ghi");
917
918            opts.separators = "_";
919            result = kebab_case_with_options("abc-def-ghi", &opts);
920            assert_eq!(result, "abc--def--ghi");
921        }
922
923        #[test]
924        fn convert_train_case() {
925            let mut opts = Options {
926                separate_before_non_alphabets: true,
927                separate_after_non_alphabets: false,
928                separators: "-",
929                keep: "",
930            };
931
932            let mut result = kebab_case_with_options("Abc-Def-Ghi", &opts);
933            assert_eq!(result, "abc-def-ghi");
934
935            opts.separators = "_";
936            result = kebab_case_with_options("Abc-Def-Ghi", &opts);
937            assert_eq!(result, "abc---def---ghi");
938        }
939
940        #[test]
941        fn convert_macro_case() {
942            let mut opts = Options {
943                separate_before_non_alphabets: true,
944                separate_after_non_alphabets: false,
945                separators: "_",
946                keep: "",
947            };
948
949            let mut result = kebab_case_with_options("ABC_DEF_GHI", &opts);
950            assert_eq!(result, "abc-def-ghi");
951
952            opts.separators = "-";
953            result = kebab_case_with_options("ABC_DEF_GHI", &opts);
954            assert_eq!(result, "abc-_def-_ghi");
955        }
956
957        #[test]
958        fn convert_cobol_case() {
959            let mut opts = Options {
960                separate_before_non_alphabets: true,
961                separate_after_non_alphabets: false,
962                separators: "-",
963                keep: "",
964            };
965
966            let mut result = kebab_case_with_options("ABC-DEF-GHI", &opts);
967            assert_eq!(result, "abc-def-ghi");
968
969            opts.separators = "_";
970            result = kebab_case_with_options("ABC-DEF-GHI", &opts);
971            assert_eq!(result, "abc--def--ghi");
972        }
973
974        #[test]
975        fn convert_with_keeping_digits() {
976            let mut opts = Options {
977                separate_before_non_alphabets: true,
978                separate_after_non_alphabets: false,
979                separators: "-",
980                keep: "",
981            };
982
983            let mut result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
984            assert_eq!(result, "abc-123-456def-g-89hi-jkl-mn-12");
985
986            opts.separators = "_";
987            result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
988            assert_eq!(result, "abc-123-456def-g-89hi-jkl-mn-12");
989        }
990
991        #[test]
992        fn convert_with_symbols_as_separators() {
993            let opts = Options {
994                separate_before_non_alphabets: true,
995                separate_after_non_alphabets: false,
996                separators: ":@$&()/",
997                keep: "",
998            };
999
1000            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
1001            assert_eq!(result, ".abc-~!-def-#-ghi-%-jk-lm-no-?");
1002        }
1003
1004        #[test]
1005        fn convert_when_starting_with_digit() {
1006            let opts = Options {
1007                separate_before_non_alphabets: true,
1008                separate_after_non_alphabets: false,
1009                separators: "-",
1010                keep: "",
1011            };
1012
1013            let result = kebab_case_with_options("123abc456def", &opts);
1014            assert_eq!(result, "123abc-456def");
1015
1016            let result = kebab_case_with_options("123ABC456DEF", &opts);
1017            assert_eq!(result, "123abc-456def");
1018        }
1019
1020        #[test]
1021        fn convert_empty_string() {
1022            let opts = Options {
1023                separate_before_non_alphabets: true,
1024                separate_after_non_alphabets: false,
1025                separators: "-_",
1026                keep: "",
1027            };
1028
1029            let result = kebab_case_with_options("", &opts);
1030            assert_eq!(result, "");
1031        }
1032
1033        #[test]
1034        fn alphabets_and_numbers_in_separators_are_no_effect() {
1035            let opts = Options {
1036                separate_before_non_alphabets: true,
1037                separate_after_non_alphabets: false,
1038                separators: "-b2",
1039                keep: "",
1040            };
1041
1042            let result = kebab_case_with_options("abc123def", &opts);
1043            assert_eq!(result, "abc-123def");
1044        }
1045    }
1046
1047    mod non_alphabets_as_tail_of_a_word_with_separators {
1048        use super::*;
1049
1050        #[test]
1051        fn convert_camel_case() {
1052            let opts = Options {
1053                separate_before_non_alphabets: false,
1054                separate_after_non_alphabets: true,
1055                separators: "-_",
1056                keep: "",
1057            };
1058
1059            let result = kebab_case_with_options("abcDefGHIjk", &opts);
1060            assert_eq!(result, "abc-def-gh-ijk");
1061        }
1062
1063        #[test]
1064        fn convert_pascal_case() {
1065            let opts = Options {
1066                separate_before_non_alphabets: false,
1067                separate_after_non_alphabets: true,
1068                separators: "-_",
1069                keep: "",
1070            };
1071
1072            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
1073            assert_eq!(result, "abc-def-gh-ijk");
1074        }
1075
1076        #[test]
1077        fn convert_snake_case() {
1078            let mut opts = Options {
1079                separate_before_non_alphabets: false,
1080                separate_after_non_alphabets: true,
1081                separators: "_",
1082                keep: "",
1083            };
1084
1085            let mut result = kebab_case_with_options("abc_def_ghi", &opts);
1086            assert_eq!(result, "abc-def-ghi");
1087
1088            opts.separators = "-";
1089            result = kebab_case_with_options("abc_def_ghi", &opts);
1090            assert_eq!(result, "abc_-def_-ghi");
1091        }
1092
1093        #[test]
1094        fn convert_kebab_case() {
1095            let mut opts = Options {
1096                separate_before_non_alphabets: false,
1097                separate_after_non_alphabets: true,
1098                separators: "-",
1099                keep: "",
1100            };
1101
1102            let mut result = kebab_case_with_options("abc-def-ghi", &opts);
1103            assert_eq!(result, "abc-def-ghi");
1104
1105            opts.separators = "_";
1106            result = kebab_case_with_options("abc-def-ghi", &opts);
1107            assert_eq!(result, "abc--def--ghi");
1108        }
1109
1110        #[test]
1111        fn convert_train_case() {
1112            let mut opts = Options {
1113                separate_before_non_alphabets: false,
1114                separate_after_non_alphabets: true,
1115                separators: "-",
1116                keep: "",
1117            };
1118
1119            let mut result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1120            assert_eq!(result, "abc-def-ghi");
1121
1122            opts.separators = "_";
1123            result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1124            assert_eq!(result, "abc--def--ghi");
1125        }
1126
1127        #[test]
1128        fn convert_macro_case() {
1129            let mut opts = Options {
1130                separate_before_non_alphabets: false,
1131                separate_after_non_alphabets: true,
1132                separators: "_",
1133                keep: "",
1134            };
1135
1136            let mut result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1137            assert_eq!(result, "abc-def-ghi");
1138
1139            opts.separators = "-";
1140            result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1141            assert_eq!(result, "abc_-def_-ghi");
1142        }
1143
1144        #[test]
1145        fn convert_cobol_case() {
1146            let mut opts = Options {
1147                separate_before_non_alphabets: false,
1148                separate_after_non_alphabets: true,
1149                separators: "-",
1150                keep: "",
1151            };
1152
1153            let mut result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1154            assert_eq!(result, "abc-def-ghi");
1155
1156            opts.separators = "_";
1157            result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1158            assert_eq!(result, "abc--def--ghi");
1159        }
1160
1161        #[test]
1162        fn convert_with_keeping_digits() {
1163            let mut opts = Options {
1164                separate_before_non_alphabets: false,
1165                separate_after_non_alphabets: true,
1166                separators: "-",
1167                keep: "",
1168            };
1169
1170            let mut result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1171            assert_eq!(result, "abc123-456-def-g89-hi-jkl-mn12");
1172
1173            opts.separators = "_";
1174            result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1175            assert_eq!(result, "abc123-456-def-g89-hi-jkl-mn12");
1176        }
1177
1178        #[test]
1179        fn convert_with_symbols_as_separators() {
1180            let opts = Options {
1181                separate_before_non_alphabets: false,
1182                separate_after_non_alphabets: true,
1183                separators: ":@$&()/",
1184                keep: "",
1185            };
1186
1187            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
1188            assert_eq!(result, ".-abc~!-def#-ghi%-jk-lm-no-?");
1189        }
1190
1191        #[test]
1192        fn convert_when_starting_with_digit() {
1193            let opts = Options {
1194                separate_before_non_alphabets: false,
1195                separate_after_non_alphabets: true,
1196                separators: "-",
1197                keep: "",
1198            };
1199
1200            let result = kebab_case_with_options("123abc456def", &opts);
1201            assert_eq!(result, "123-abc456-def");
1202
1203            let result = kebab_case_with_options("123ABC456DEF", &opts);
1204            assert_eq!(result, "123-abc456-def");
1205        }
1206
1207        #[test]
1208        fn convert_empty_string() {
1209            let opts = Options {
1210                separate_before_non_alphabets: false,
1211                separate_after_non_alphabets: true,
1212                separators: "-_",
1213                keep: "",
1214            };
1215
1216            let result = kebab_case_with_options("", &opts);
1217            assert_eq!(result, "");
1218        }
1219
1220        #[test]
1221        fn alphabets_and_numbers_in_separators_are_no_effect() {
1222            let opts = Options {
1223                separate_before_non_alphabets: false,
1224                separate_after_non_alphabets: true,
1225                separators: "-b2",
1226                keep: "",
1227            };
1228
1229            let result = kebab_case_with_options("abc123def", &opts);
1230            assert_eq!(result, "abc123-def");
1231        }
1232    }
1233
1234    mod non_alphabets_as_a_word_with_separators {
1235        use super::*;
1236
1237        #[test]
1238        fn convert_camel_case() {
1239            let opts = Options {
1240                separate_before_non_alphabets: true,
1241                separate_after_non_alphabets: true,
1242                separators: "-_",
1243                keep: "",
1244            };
1245
1246            let result = kebab_case_with_options("abcDefGHIjk", &opts);
1247            assert_eq!(result, "abc-def-gh-ijk");
1248        }
1249
1250        #[test]
1251        fn convert_pascal_case() {
1252            let opts = Options {
1253                separate_before_non_alphabets: true,
1254                separate_after_non_alphabets: true,
1255                separators: "-_",
1256                keep: "",
1257            };
1258
1259            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
1260            assert_eq!(result, "abc-def-gh-ijk");
1261        }
1262
1263        #[test]
1264        fn convert_snake_case() {
1265            let mut opts = Options {
1266                separate_before_non_alphabets: true,
1267                separate_after_non_alphabets: true,
1268                separators: "_",
1269                keep: "",
1270            };
1271
1272            let mut result = kebab_case_with_options("abc_def_ghi", &opts);
1273            assert_eq!(result, "abc-def-ghi");
1274
1275            opts.separators = "-";
1276            result = kebab_case_with_options("abc_def_ghi", &opts);
1277            assert_eq!(result, "abc-_-def-_-ghi");
1278        }
1279
1280        #[test]
1281        fn convert_kebab_case() {
1282            let mut opts = Options {
1283                separate_before_non_alphabets: true,
1284                separate_after_non_alphabets: true,
1285                separators: "-",
1286                keep: "",
1287            };
1288
1289            let mut result = kebab_case_with_options("abc-def-ghi", &opts);
1290            assert_eq!(result, "abc-def-ghi");
1291
1292            opts.separators = "_";
1293            result = kebab_case_with_options("abc-def-ghi", &opts);
1294            assert_eq!(result, "abc---def---ghi");
1295        }
1296
1297        #[test]
1298        fn convert_train_case() {
1299            let mut opts = Options {
1300                separate_before_non_alphabets: true,
1301                separate_after_non_alphabets: true,
1302                separators: "-",
1303                keep: "",
1304            };
1305
1306            let mut result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1307            assert_eq!(result, "abc-def-ghi");
1308
1309            opts.separators = "_";
1310            result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1311            assert_eq!(result, "abc---def---ghi");
1312        }
1313
1314        #[test]
1315        fn convert_macro_case() {
1316            let mut opts = Options {
1317                separate_before_non_alphabets: true,
1318                separate_after_non_alphabets: true,
1319                separators: "_",
1320                keep: "",
1321            };
1322
1323            let mut result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1324            assert_eq!(result, "abc-def-ghi");
1325
1326            opts.separators = "-";
1327            result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1328            assert_eq!(result, "abc-_-def-_-ghi");
1329        }
1330
1331        #[test]
1332        fn convert_cobol_case() {
1333            let mut opts = Options {
1334                separate_before_non_alphabets: true,
1335                separate_after_non_alphabets: true,
1336                separators: "-",
1337                keep: "",
1338            };
1339
1340            let mut result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1341            assert_eq!(result, "abc-def-ghi");
1342
1343            opts.separators = "_";
1344            result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1345            assert_eq!(result, "abc---def---ghi");
1346        }
1347
1348        #[test]
1349        fn convert_with_keeping_digits() {
1350            let mut opts = Options {
1351                separate_before_non_alphabets: true,
1352                separate_after_non_alphabets: true,
1353                separators: "-",
1354                keep: "",
1355            };
1356
1357            let mut result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1358            assert_eq!(result, "abc-123-456-def-g-89-hi-jkl-mn-12");
1359
1360            opts.separators = "_";
1361            result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1362            assert_eq!(result, "abc-123-456-def-g-89-hi-jkl-mn-12");
1363        }
1364
1365        #[test]
1366        fn convert_with_symbols_as_separators() {
1367            let opts = Options {
1368                separate_before_non_alphabets: true,
1369                separate_after_non_alphabets: true,
1370                separators: ":@$&()/",
1371                keep: "",
1372            };
1373
1374            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
1375            assert_eq!(result, ".-abc-~!-def-#-ghi-%-jk-lm-no-?");
1376        }
1377
1378        #[test]
1379        fn convert_when_starting_with_digit() {
1380            let opts = Options {
1381                separate_before_non_alphabets: true,
1382                separate_after_non_alphabets: true,
1383                separators: "-",
1384                keep: "",
1385            };
1386
1387            let result = kebab_case_with_options("123abc456def", &opts);
1388            assert_eq!(result, "123-abc-456-def");
1389
1390            let result = kebab_case_with_options("123ABC456DEF", &opts);
1391            assert_eq!(result, "123-abc-456-def");
1392        }
1393
1394        #[test]
1395        fn convert_empty_string() {
1396            let opts = Options {
1397                separate_before_non_alphabets: true,
1398                separate_after_non_alphabets: true,
1399                separators: "-_",
1400                keep: "",
1401            };
1402
1403            let result = kebab_case_with_options("", &opts);
1404            assert_eq!(result, "");
1405        }
1406
1407        #[test]
1408        fn alphabets_and_numbers_in_separators_are_no_effect() {
1409            let opts = Options {
1410                separate_before_non_alphabets: true,
1411                separate_after_non_alphabets: true,
1412                separators: "-b2",
1413                keep: "",
1414            };
1415
1416            let result = kebab_case_with_options("abc123def", &opts);
1417            assert_eq!(result, "abc-123-def");
1418        }
1419    }
1420
1421    mod non_alphabets_as_part_of_a_word_with_separators {
1422        use super::*;
1423
1424        #[test]
1425        fn convert_camel_case() {
1426            let opts = Options {
1427                separate_before_non_alphabets: false,
1428                separate_after_non_alphabets: false,
1429                separators: "-_",
1430                keep: "",
1431            };
1432
1433            let result = kebab_case_with_options("abcDefGHIjk", &opts);
1434            assert_eq!(result, "abc-def-gh-ijk");
1435        }
1436
1437        #[test]
1438        fn convert_pascal_case() {
1439            let opts = Options {
1440                separate_before_non_alphabets: false,
1441                separate_after_non_alphabets: false,
1442                separators: "-_",
1443                keep: "",
1444            };
1445
1446            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
1447            assert_eq!(result, "abc-def-gh-ijk");
1448        }
1449
1450        #[test]
1451        fn convert_snake_case() {
1452            let mut opts = Options {
1453                separate_before_non_alphabets: false,
1454                separate_after_non_alphabets: false,
1455                separators: "_",
1456                keep: "",
1457            };
1458
1459            let mut result = kebab_case_with_options("abc_def_ghi", &opts);
1460            assert_eq!(result, "abc-def-ghi");
1461
1462            opts.separators = "-";
1463            result = kebab_case_with_options("abc_def_ghi", &opts);
1464            assert_eq!(result, "abc_def_ghi");
1465        }
1466
1467        #[test]
1468        fn convert_kebab_case() {
1469            let mut opts = Options {
1470                separate_before_non_alphabets: false,
1471                separate_after_non_alphabets: false,
1472                separators: "-",
1473                keep: "",
1474            };
1475
1476            let mut result = kebab_case_with_options("abc-def-ghi", &opts);
1477            assert_eq!(result, "abc-def-ghi");
1478
1479            opts.separators = "_";
1480            result = kebab_case_with_options("abc-def-ghi", &opts);
1481            assert_eq!(result, "abc-def-ghi");
1482        }
1483
1484        #[test]
1485        fn convert_train_case() {
1486            let mut opts = Options {
1487                separate_before_non_alphabets: false,
1488                separate_after_non_alphabets: false,
1489                separators: "-",
1490                keep: "",
1491            };
1492
1493            let mut result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1494            assert_eq!(result, "abc-def-ghi");
1495
1496            opts.separators = "_";
1497            result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1498            assert_eq!(result, "abc--def--ghi");
1499        }
1500
1501        #[test]
1502        fn convert_macro_case() {
1503            let mut opts = Options {
1504                separate_before_non_alphabets: false,
1505                separate_after_non_alphabets: false,
1506                separators: "_",
1507                keep: "",
1508            };
1509
1510            let mut result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1511            assert_eq!(result, "abc-def-ghi");
1512
1513            opts.separators = "-";
1514            result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1515            assert_eq!(result, "abc_def_ghi");
1516        }
1517
1518        #[test]
1519        fn convert_cobol_case() {
1520            let mut opts = Options {
1521                separate_before_non_alphabets: false,
1522                separate_after_non_alphabets: false,
1523                separators: "-",
1524                keep: "",
1525            };
1526
1527            let mut result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1528            assert_eq!(result, "abc-def-ghi");
1529
1530            opts.separators = "_";
1531            result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1532            assert_eq!(result, "abc-def-ghi");
1533        }
1534
1535        #[test]
1536        fn convert_with_keeping_digits() {
1537            let mut opts = Options {
1538                separate_before_non_alphabets: false,
1539                separate_after_non_alphabets: false,
1540                separators: "-",
1541                keep: "",
1542            };
1543
1544            let mut result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1545            assert_eq!(result, "abc123-456def-g89hi-jkl-mn12");
1546
1547            opts.separators = "_";
1548            result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1549            assert_eq!(result, "abc123-456def-g89hi-jkl-mn12");
1550        }
1551
1552        #[test]
1553        fn convert_with_symbols_as_separators() {
1554            let opts = Options {
1555                separate_before_non_alphabets: false,
1556                separate_after_non_alphabets: false,
1557                separators: ":@$&()/",
1558                keep: "",
1559            };
1560
1561            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
1562            assert_eq!(result, ".abc~!-def#-ghi%-jk-lm-no-?");
1563        }
1564
1565        #[test]
1566        fn convert_when_starting_with_digit() {
1567            let opts = Options {
1568                separate_before_non_alphabets: false,
1569                separate_after_non_alphabets: false,
1570                separators: "-",
1571                keep: "",
1572            };
1573
1574            let result = kebab_case_with_options("123abc456def", &opts);
1575            assert_eq!(result, "123abc456def");
1576
1577            let result = kebab_case_with_options("123ABC456DEF", &opts);
1578            assert_eq!(result, "123abc456def");
1579        }
1580
1581        #[test]
1582        fn convert_empty_string() {
1583            let opts = Options {
1584                separate_before_non_alphabets: false,
1585                separate_after_non_alphabets: false,
1586                separators: "-_",
1587                keep: "",
1588            };
1589
1590            let result = kebab_case_with_options("", &opts);
1591            assert_eq!(result, "");
1592        }
1593
1594        #[test]
1595        fn alphabets_and_numbers_in_separators_are_no_effect() {
1596            let opts = Options {
1597                separate_before_non_alphabets: false,
1598                separate_after_non_alphabets: false,
1599                separators: "-b2",
1600                keep: "",
1601            };
1602
1603            let result = kebab_case_with_options("abc123def", &opts);
1604            assert_eq!(result, "abc123def");
1605        }
1606    }
1607
1608    mod non_alphabets_as_head_of_a_word_with_kept_characters {
1609        use super::*;
1610
1611        #[test]
1612        fn convert_camel_case() {
1613            let opts = Options {
1614                separate_before_non_alphabets: true,
1615                separate_after_non_alphabets: false,
1616                separators: "",
1617                keep: "-_",
1618            };
1619
1620            let result = kebab_case_with_options("abcDefGHIjk", &opts);
1621            assert_eq!(result, "abc-def-gh-ijk");
1622        }
1623
1624        #[test]
1625        fn convert_pascal_case() {
1626            let opts = Options {
1627                separate_before_non_alphabets: true,
1628                separate_after_non_alphabets: false,
1629                separators: "",
1630                keep: "-_",
1631            };
1632
1633            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
1634            assert_eq!(result, "abc-def-gh-ijk");
1635        }
1636
1637        #[test]
1638        fn convert_snake_case() {
1639            let mut opts = Options {
1640                separate_before_non_alphabets: true,
1641                separate_after_non_alphabets: false,
1642                separators: "",
1643                keep: "-",
1644            };
1645
1646            let mut result = kebab_case_with_options("abc_def_ghi", &opts);
1647            assert_eq!(result, "abc-def-ghi");
1648
1649            opts.keep = "_";
1650            result = kebab_case_with_options("abc_def_ghi", &opts);
1651            assert_eq!(result, "abc-_def-_ghi");
1652        }
1653
1654        #[test]
1655        fn convert_kebab_case() {
1656            let mut opts = Options {
1657                separate_before_non_alphabets: true,
1658                separate_after_non_alphabets: false,
1659                separators: "",
1660                keep: "_",
1661            };
1662
1663            let mut result = kebab_case_with_options("abc-def-ghi", &opts);
1664            assert_eq!(result, "abc-def-ghi");
1665
1666            opts.keep = "-";
1667            result = kebab_case_with_options("abc-def-ghi", &opts);
1668            assert_eq!(result, "abc--def--ghi");
1669        }
1670
1671        #[test]
1672        fn convert_train_case() {
1673            let mut opts = Options {
1674                separate_before_non_alphabets: true,
1675                separate_after_non_alphabets: false,
1676                separators: "",
1677                keep: "_",
1678            };
1679
1680            let mut result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1681            assert_eq!(result, "abc-def-ghi");
1682
1683            opts.keep = "-";
1684            result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1685            assert_eq!(result, "abc---def---ghi");
1686        }
1687
1688        #[test]
1689        fn convert_macro_case() {
1690            let mut opts = Options {
1691                separate_before_non_alphabets: true,
1692                separate_after_non_alphabets: false,
1693                separators: "",
1694                keep: "-",
1695            };
1696
1697            let mut result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1698            assert_eq!(result, "abc-def-ghi");
1699
1700            opts.keep = "_";
1701            result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1702            assert_eq!(result, "abc-_def-_ghi");
1703        }
1704
1705        #[test]
1706        fn convert_cobol_case() {
1707            let mut opts = Options {
1708                separate_before_non_alphabets: true,
1709                separate_after_non_alphabets: false,
1710                separators: "",
1711                keep: "_",
1712            };
1713
1714            let mut result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1715            assert_eq!(result, "abc-def-ghi");
1716
1717            opts.keep = "-";
1718            result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1719            assert_eq!(result, "abc--def--ghi");
1720        }
1721
1722        #[test]
1723        fn convert_with_keeping_digits() {
1724            let mut opts = Options {
1725                separate_before_non_alphabets: true,
1726                separate_after_non_alphabets: false,
1727                separators: "",
1728                keep: "_",
1729            };
1730
1731            let mut result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1732            assert_eq!(result, "abc-123-456def-g-89hi-jkl-mn-12");
1733
1734            opts.keep = "-";
1735            result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1736            assert_eq!(result, "abc-123-456def-g-89hi-jkl-mn-12");
1737        }
1738
1739        #[test]
1740        fn convert_when_starting_with_digit() {
1741            let opts = Options {
1742                separate_before_non_alphabets: true,
1743                separate_after_non_alphabets: false,
1744                separators: "",
1745                keep: "-",
1746            };
1747
1748            let result = kebab_case_with_options("123abc456def", &opts);
1749            assert_eq!(result, "123abc-456def");
1750
1751            let result = kebab_case_with_options("123ABC456DEF", &opts);
1752            assert_eq!(result, "123abc-456def");
1753        }
1754
1755        #[test]
1756        fn convert_with_symbols_as_separators() {
1757            let opts = Options {
1758                separate_before_non_alphabets: true,
1759                separate_after_non_alphabets: false,
1760                separators: "",
1761                keep: ".~!#%?",
1762            };
1763
1764            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
1765            assert_eq!(result, ".abc-~!-def-#-ghi-%-jk-lm-no-?");
1766        }
1767
1768        #[test]
1769        fn convert_empty_string() {
1770            let opts = Options {
1771                separate_before_non_alphabets: true,
1772                separate_after_non_alphabets: false,
1773                separators: "",
1774                keep: "-_",
1775            };
1776
1777            let result = kebab_case_with_options("", &opts);
1778            assert_eq!(result, "");
1779        }
1780    }
1781
1782    mod non_alphabets_as_tail_of_a_word_with_kept_characters {
1783        use super::*;
1784
1785        #[test]
1786        fn convert_camel_case() {
1787            let opts = Options {
1788                separate_before_non_alphabets: false,
1789                separate_after_non_alphabets: true,
1790                separators: "",
1791                keep: "-_",
1792            };
1793
1794            let result = kebab_case_with_options("abcDefGHIjk", &opts);
1795            assert_eq!(result, "abc-def-gh-ijk");
1796        }
1797
1798        #[test]
1799        fn convert_pascal_case() {
1800            let opts = Options {
1801                separate_before_non_alphabets: false,
1802                separate_after_non_alphabets: true,
1803                separators: "",
1804                keep: "-_",
1805            };
1806
1807            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
1808            assert_eq!(result, "abc-def-gh-ijk");
1809        }
1810
1811        #[test]
1812        fn convert_snake_case() {
1813            let mut opts = Options {
1814                separate_before_non_alphabets: false,
1815                separate_after_non_alphabets: true,
1816                separators: "",
1817                keep: "-",
1818            };
1819
1820            let mut result = kebab_case_with_options("abc_def_ghi", &opts);
1821            assert_eq!(result, "abc-def-ghi");
1822
1823            opts.keep = "_";
1824            result = kebab_case_with_options("abc_def_ghi", &opts);
1825            assert_eq!(result, "abc_-def_-ghi");
1826        }
1827
1828        #[test]
1829        fn convert_kebab_case() {
1830            let mut opts = Options {
1831                separate_before_non_alphabets: false,
1832                separate_after_non_alphabets: true,
1833                separators: "",
1834                keep: "_",
1835            };
1836
1837            let mut result = kebab_case_with_options("abc-def-ghi", &opts);
1838            assert_eq!(result, "abc-def-ghi");
1839
1840            opts.keep = "-";
1841            result = kebab_case_with_options("abc-def-ghi", &opts);
1842            assert_eq!(result, "abc--def--ghi");
1843        }
1844
1845        #[test]
1846        fn convert_train_case() {
1847            let mut opts = Options {
1848                separate_before_non_alphabets: false,
1849                separate_after_non_alphabets: true,
1850                separators: "",
1851                keep: "_",
1852            };
1853
1854            let mut result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1855            assert_eq!(result, "abc-def-ghi");
1856
1857            opts.keep = "-";
1858            result = kebab_case_with_options("Abc-Def-Ghi", &opts);
1859            assert_eq!(result, "abc--def--ghi");
1860        }
1861
1862        #[test]
1863        fn convert_macro_case() {
1864            let mut opts = Options {
1865                separate_before_non_alphabets: false,
1866                separate_after_non_alphabets: true,
1867                separators: "",
1868                keep: "-",
1869            };
1870
1871            let mut result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1872            assert_eq!(result, "abc-def-ghi");
1873
1874            opts.keep = "_";
1875            result = kebab_case_with_options("ABC_DEF_GHI", &opts);
1876            assert_eq!(result, "abc_-def_-ghi");
1877        }
1878
1879        #[test]
1880        fn convert_cobol_case() {
1881            let mut opts = Options {
1882                separate_before_non_alphabets: false,
1883                separate_after_non_alphabets: true,
1884                separators: "",
1885                keep: "_",
1886            };
1887
1888            let mut result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1889            assert_eq!(result, "abc-def-ghi");
1890
1891            opts.keep = "-";
1892            result = kebab_case_with_options("ABC-DEF-GHI", &opts);
1893            assert_eq!(result, "abc--def--ghi");
1894        }
1895
1896        #[test]
1897        fn convert_with_keeping_digits() {
1898            let mut opts = Options {
1899                separate_before_non_alphabets: false,
1900                separate_after_non_alphabets: true,
1901                separators: "",
1902                keep: "_",
1903            };
1904
1905            let mut result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1906            assert_eq!(result, "abc123-456-def-g89-hi-jkl-mn12");
1907
1908            opts.keep = "-";
1909            result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
1910            assert_eq!(result, "abc123-456-def-g89-hi-jkl-mn12");
1911        }
1912
1913        #[test]
1914        fn convert_when_starting_with_digit() {
1915            let mut opts = Options {
1916                separate_before_non_alphabets: false,
1917                separate_after_non_alphabets: true,
1918                separators: "",
1919                keep: "-",
1920            };
1921
1922            let result = kebab_case_with_options("123abc456def", &opts);
1923            assert_eq!(result, "123-abc456-def");
1924
1925            opts.keep = "_";
1926            let result = kebab_case_with_options("123ABC456DEF", &opts);
1927            assert_eq!(result, "123-abc456-def");
1928        }
1929
1930        #[test]
1931        fn convert_with_symbols_as_separators() {
1932            let opts = Options {
1933                separate_before_non_alphabets: false,
1934                separate_after_non_alphabets: true,
1935                separators: "",
1936                keep: ".~!#%?",
1937            };
1938
1939            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
1940            assert_eq!(result, ".-abc~!-def#-ghi%-jk-lm-no-?");
1941        }
1942
1943        #[test]
1944        fn convert_empty_string() {
1945            let opts = Options {
1946                separate_before_non_alphabets: false,
1947                separate_after_non_alphabets: true,
1948                separators: "",
1949                keep: "-_",
1950            };
1951
1952            let result = kebab_case_with_options("", &opts);
1953            assert_eq!(result, "");
1954        }
1955    }
1956
1957    mod non_alphabets_as_a_word_with_kept_characters {
1958        use super::*;
1959
1960        #[test]
1961        fn convert_camel_case() {
1962            let opts = Options {
1963                separate_before_non_alphabets: true,
1964                separate_after_non_alphabets: true,
1965                separators: "",
1966                keep: "-_",
1967            };
1968
1969            let result = kebab_case_with_options("abcDefGHIjk", &opts);
1970            assert_eq!(result, "abc-def-gh-ijk");
1971        }
1972
1973        #[test]
1974        fn convert_pascal_case() {
1975            let opts = Options {
1976                separate_before_non_alphabets: true,
1977                separate_after_non_alphabets: true,
1978                separators: "",
1979                keep: "-_",
1980            };
1981
1982            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
1983            assert_eq!(result, "abc-def-gh-ijk");
1984        }
1985
1986        #[test]
1987        fn convert_snake_case() {
1988            let mut opts = Options {
1989                separate_before_non_alphabets: true,
1990                separate_after_non_alphabets: true,
1991                separators: "",
1992                keep: "-",
1993            };
1994
1995            let mut result = kebab_case_with_options("abc_def_ghi", &opts);
1996            assert_eq!(result, "abc-def-ghi");
1997
1998            opts.keep = "_";
1999            result = kebab_case_with_options("abc_def_ghi", &opts);
2000            assert_eq!(result, "abc-_-def-_-ghi");
2001        }
2002
2003        #[test]
2004        fn convert_kebab_case() {
2005            let mut opts = Options {
2006                separate_before_non_alphabets: true,
2007                separate_after_non_alphabets: true,
2008                separators: "",
2009                keep: "_",
2010            };
2011
2012            let mut result = kebab_case_with_options("abc-def-ghi", &opts);
2013            assert_eq!(result, "abc-def-ghi");
2014
2015            opts.keep = "-";
2016            result = kebab_case_with_options("abc-def-ghi", &opts);
2017            assert_eq!(result, "abc---def---ghi");
2018        }
2019
2020        #[test]
2021        fn convert_train_case() {
2022            let mut opts = Options {
2023                separate_before_non_alphabets: true,
2024                separate_after_non_alphabets: true,
2025                separators: "",
2026                keep: "_",
2027            };
2028
2029            let mut result = kebab_case_with_options("Abc-Def-Ghi", &opts);
2030            assert_eq!(result, "abc-def-ghi");
2031
2032            opts.keep = "-";
2033            result = kebab_case_with_options("Abc-Def-Ghi", &opts);
2034            assert_eq!(result, "abc---def---ghi");
2035        }
2036
2037        #[test]
2038        fn convert_macro_case() {
2039            let mut opts = Options {
2040                separate_before_non_alphabets: true,
2041                separate_after_non_alphabets: true,
2042                separators: "",
2043                keep: "-",
2044            };
2045
2046            let mut result = kebab_case_with_options("ABC_DEF_GHI", &opts);
2047            assert_eq!(result, "abc-def-ghi");
2048
2049            opts.keep = "_";
2050            result = kebab_case_with_options("ABC_DEF_GHI", &opts);
2051            assert_eq!(result, "abc-_-def-_-ghi");
2052        }
2053
2054        #[test]
2055        fn convert_cobol_case() {
2056            let mut opts = Options {
2057                separate_before_non_alphabets: true,
2058                separate_after_non_alphabets: true,
2059                separators: "",
2060                keep: "_",
2061            };
2062
2063            let mut result = kebab_case_with_options("ABC-DEF-GHI", &opts);
2064            assert_eq!(result, "abc-def-ghi");
2065
2066            opts.keep = "-";
2067            result = kebab_case_with_options("ABC-DEF-GHI", &opts);
2068            assert_eq!(result, "abc---def---ghi");
2069        }
2070
2071        #[test]
2072        fn convert_with_keeping_digits() {
2073            let mut opts = Options {
2074                separate_before_non_alphabets: true,
2075                separate_after_non_alphabets: true,
2076                separators: "",
2077                keep: "_",
2078            };
2079
2080            let mut result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
2081            assert_eq!(result, "abc-123-456-def-g-89-hi-jkl-mn-12");
2082
2083            opts.keep = "-";
2084            result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
2085            assert_eq!(result, "abc-123-456-def-g-89-hi-jkl-mn-12");
2086        }
2087
2088        #[test]
2089        fn convert_when_starting_with_digit() {
2090            let opts = Options {
2091                separate_before_non_alphabets: true,
2092                separate_after_non_alphabets: true,
2093                separators: "",
2094                keep: "-",
2095            };
2096
2097            let result = kebab_case_with_options("123abc456def", &opts);
2098            assert_eq!(result, "123-abc-456-def");
2099
2100            let result = kebab_case_with_options("123ABC456DEF", &opts);
2101            assert_eq!(result, "123-abc-456-def");
2102        }
2103
2104        #[test]
2105        fn convert_with_symbols_as_separators() {
2106            let opts = Options {
2107                separate_before_non_alphabets: true,
2108                separate_after_non_alphabets: true,
2109                separators: "",
2110                keep: ".~!#%?",
2111            };
2112
2113            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
2114            assert_eq!(result, ".-abc-~!-def-#-ghi-%-jk-lm-no-?");
2115        }
2116
2117        #[test]
2118        fn convert_empty_string() {
2119            let opts = Options {
2120                separate_before_non_alphabets: true,
2121                separate_after_non_alphabets: true,
2122                separators: "",
2123                keep: "-_",
2124            };
2125
2126            let result = kebab_case_with_options("", &opts);
2127            assert_eq!(result, "");
2128        }
2129    }
2130
2131    mod non_alphabets_as_part_of_a_word_with_kept_characters {
2132        use super::*;
2133
2134        #[test]
2135        fn convert_camel_case() {
2136            let opts = Options {
2137                separate_before_non_alphabets: false,
2138                separate_after_non_alphabets: false,
2139                separators: "",
2140                keep: "-_",
2141            };
2142
2143            let result = kebab_case_with_options("abcDefGHIjk", &opts);
2144            assert_eq!(result, "abc-def-gh-ijk");
2145        }
2146
2147        #[test]
2148        fn convert_pascal_case() {
2149            let opts = Options {
2150                separate_before_non_alphabets: false,
2151                separate_after_non_alphabets: false,
2152                separators: "",
2153                keep: "-_",
2154            };
2155
2156            let result = kebab_case_with_options("AbcDefGHIjk", &opts);
2157            assert_eq!(result, "abc-def-gh-ijk");
2158        }
2159
2160        #[test]
2161        fn convert_snake_case() {
2162            let mut opts = Options {
2163                separate_before_non_alphabets: false,
2164                separate_after_non_alphabets: false,
2165                separators: "",
2166                keep: "-",
2167            };
2168
2169            let mut result = kebab_case_with_options("abc_def_ghi", &opts);
2170            assert_eq!(result, "abc-def-ghi");
2171
2172            opts.keep = "_";
2173            result = kebab_case_with_options("abc_def_ghi", &opts);
2174            assert_eq!(result, "abc_def_ghi");
2175        }
2176
2177        #[test]
2178        fn convert_kebab_case() {
2179            let mut opts = Options {
2180                separate_before_non_alphabets: false,
2181                separate_after_non_alphabets: false,
2182                separators: "",
2183                keep: "_",
2184            };
2185
2186            let mut result = kebab_case_with_options("abc-def-ghi", &opts);
2187            assert_eq!(result, "abc-def-ghi");
2188
2189            opts.keep = "-";
2190            result = kebab_case_with_options("abc-def-ghi", &opts);
2191            assert_eq!(result, "abc-def-ghi");
2192        }
2193
2194        #[test]
2195        fn convert_train_case() {
2196            let mut opts = Options {
2197                separate_before_non_alphabets: false,
2198                separate_after_non_alphabets: false,
2199                separators: "",
2200                keep: "_",
2201            };
2202
2203            let mut result = kebab_case_with_options("Abc-Def-Ghi", &opts);
2204            assert_eq!(result, "abc-def-ghi");
2205
2206            opts.keep = "-";
2207            result = kebab_case_with_options("Abc-Def-Ghi", &opts);
2208            assert_eq!(result, "abc--def--ghi");
2209        }
2210
2211        #[test]
2212        fn convert_macro_case() {
2213            let mut opts = Options {
2214                separate_before_non_alphabets: false,
2215                separate_after_non_alphabets: false,
2216                separators: "",
2217                keep: "-",
2218            };
2219
2220            let mut result = kebab_case_with_options("ABC_DEF_GHI", &opts);
2221            assert_eq!(result, "abc-def-ghi");
2222
2223            opts.keep = "_";
2224            result = kebab_case_with_options("ABC_DEF_GHI", &opts);
2225            assert_eq!(result, "abc_def_ghi");
2226        }
2227
2228        #[test]
2229        fn convert_cobol_case() {
2230            let mut opts = Options {
2231                separate_before_non_alphabets: false,
2232                separate_after_non_alphabets: false,
2233                separators: "",
2234                keep: "_",
2235            };
2236
2237            let mut result = kebab_case_with_options("ABC-DEF-GHI", &opts);
2238            assert_eq!(result, "abc-def-ghi");
2239
2240            opts.keep = "-";
2241            result = kebab_case_with_options("ABC-DEF-GHI", &opts);
2242            assert_eq!(result, "abc-def-ghi");
2243        }
2244
2245        #[test]
2246        fn convert_with_keeping_digits() {
2247            let mut opts = Options {
2248                separate_before_non_alphabets: false,
2249                separate_after_non_alphabets: false,
2250                separators: "",
2251                keep: "_",
2252            };
2253
2254            let mut result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
2255            assert_eq!(result, "abc123-456def-g89hi-jkl-mn12");
2256
2257            opts.keep = "-";
2258            result = kebab_case_with_options("abc123-456defG89HIJklMN12", &opts);
2259            assert_eq!(result, "abc123-456def-g89hi-jkl-mn12");
2260        }
2261
2262        #[test]
2263        fn convert_when_starting_with_digit() {
2264            let opts = Options {
2265                separate_before_non_alphabets: false,
2266                separate_after_non_alphabets: false,
2267                separators: "",
2268                keep: "-",
2269            };
2270
2271            let result = kebab_case_with_options("123abc456def", &opts);
2272            assert_eq!(result, "123abc456def");
2273
2274            let result = kebab_case_with_options("123ABC456DEF", &opts);
2275            assert_eq!(result, "123abc456def");
2276        }
2277
2278        #[test]
2279        fn convert_with_symbols_as_separators() {
2280            let opts = Options {
2281                separate_before_non_alphabets: false,
2282                separate_after_non_alphabets: false,
2283                separators: "",
2284                keep: ".~!#%?",
2285            };
2286
2287            let result = kebab_case_with_options(":.abc~!@def#$ghi%&jk(lm)no/?", &opts);
2288            assert_eq!(result, ".abc~!-def#-ghi%-jk-lm-no-?");
2289        }
2290
2291        #[test]
2292        fn convert_empty_string() {
2293            let opts = Options {
2294                separate_before_non_alphabets: false,
2295                separate_after_non_alphabets: false,
2296                separators: "",
2297                keep: "-_",
2298            };
2299
2300            let result = kebab_case_with_options("", &opts);
2301            assert_eq!(result, "");
2302        }
2303    }
2304}