string-kit
Version:
A string manipulation toolbox, featuring a string formatter (inspired by sprintf), a variable inspector (output featuring ANSI colors and HTML) and various escape functions (shell argument, regexp, html, etc).
571 lines (452 loc) • 25 kB
Markdown
## Table of Content
* [format()](#format)
* [Escape collection](#escape-collection)
* [Camel case](#camel-case)
* [Latinize](#latinize)
* [Wordwrap](#wordwrap)
* [inspect()](#inspect)
* [Title case](#title-case)
* [Misc](#misc)
* [Unicode](#unicode)
## format()
**Should perform basic examples**
```javascript
expect( format( 'Hello world' ) ).to.be( 'Hello world' ) ;
expect( format( 'Hello %s' , 'world' ) ).to.be( 'Hello world' ) ;
expect( format( 'Hello %s %s, how are you?' , 'Joe' , 'Doe' ) ).to.be( 'Hello Joe Doe, how are you?' ) ;
expect( format( 'I have %i cookies.' , 3 ) ).to.be( 'I have 3 cookies.' ) ;
expect( format( 'This company regains %d%% of market share.' , 36 ) ).to.be( 'This company regains 36% of market share.' ) ;
expect( format( '11/8=%f' , 11/8 ) ).to.be( '11/8=1.375' ) ;
expect( format( 'Binary %b %b' , 11 , 123 ) ).to.be( 'Binary 1011 1111011' ) ;
expect( format( 'Octal %o %o' , 11 , 123 ) ).to.be( 'Octal 13 173' ) ;
expect( format( 'Hexa %h %x %x' , 11 , 11 , 123 ) ).to.be( 'Hexa b 0b 7b' ) ;
expect( format( 'JSON %J' , {hello:'world',here:'is',my:{wonderful:'object'}} ) ).to.be( 'JSON {"hello":"world","here":"is","my":{"wonderful":"object"}}' ) ;
expect( format( 'Inspect %I' , {hello:'world',here:'is',my:{wonderful:'object'}} ) ).to.be( 'Inspect <Object> <object> {\n hello: "world" <string>(5)\n here: "is" <string>(2)\n my: <Object> <object> {\n wonderful: "object" <string>(6)\n }\n}\n' ) ;
//expect( format( 'Inspect %E' , new Error( 'Some error' ) ) ).to.be( '' ) ;
```
**%u should format unsigned integer**
```javascript
expect( format( '%u' , 123 ) ).to.be( '123' ) ;
expect( format( '%u' , 0 ) ).to.be( '0' ) ;
expect( format( '%u' , -123 ) ).to.be( '0' ) ;
expect( format( '%u' ) ).to.be( '0' ) ;
```
**%U should format *positive* unsigned integer**
```javascript
expect( format( '%U' , 123 ) ).to.be( '123' ) ;
expect( format( '%U' , 0 ) ).to.be( '1' ) ;
expect( format( '%U' , -123 ) ).to.be( '1' ) ;
expect( format( '%U' ) ).to.be( '1' ) ;
```
**%z should format as base64**
```javascript
expect( format( '%z' , 'some text' ) ).to.be( 'c29tZSB0ZXh0' ) ;
expect( format( '%z' , Buffer.from( 'some text' ) ) ).to.be( 'c29tZSB0ZXh0' ) ;
expect( format( '%z' , 'some longer text' ) ).to.be( 'c29tZSBsb25nZXIgdGV4dA==' ) ;
expect( format( '%z' , Buffer.from( 'some longer text' ) ) ).to.be( 'c29tZSBsb25nZXIgdGV4dA==' ) ;
expect( format( '%z' , Buffer.from( '+/c=' , 'base64' ) ) ).to.be( '+/c=' ) ;
```
**%Z should format as base64**
```javascript
expect( format( '%Z' , 'some text' ) ).to.be( 'c29tZSB0ZXh0' ) ;
expect( format( '%Z' , Buffer.from( 'some text' ) ) ).to.be( 'c29tZSB0ZXh0' ) ;
expect( format( '%Z' , 'some longer text' ) ).to.be( 'c29tZSBsb25nZXIgdGV4dA' ) ;
expect( format( '%Z' , Buffer.from( 'some longer text' ) ) ).to.be( 'c29tZSBsb25nZXIgdGV4dA' ) ;
expect( format( '%Z' , Buffer.from( '+/c=' , 'base64' ) ) ).to.be( '-_c' ) ;
```
**Should perform well the argument's index feature**
```javascript
expect( format( '%s%s%s' , 'A' , 'B' , 'C' ) ).to.be( 'ABC' ) ;
expect( format( '%+1s%-1s%s' , 'A' , 'B' , 'C' ) ).to.be( 'BAC' ) ;
expect( format( '%3s%s' , 'A' , 'B' , 'C' ) ).to.be( 'CBC' ) ;
```
**Should perform well the mode arguments feature**
```javascript
expect( format( '%[f0]f' , 1/3 ) ).to.be( '0' ) ;
expect( format( '%[f1]f' , 1/3 ) ).to.be( '0.3' ) ;
expect( format( '%[f2]f' , 1/3 ) ).to.be( '0.33' ) ;
expect( format( '%[f0]f' , 0.1 ) ).to.be( '0' ) ;
expect( format( '%[f1]f' , 0.1 ) ).to.be( '0.1' ) ;
expect( format( '%[f2]f' , 0.1 ) ).to.be( '0.10' ) ;
/* p is not finished yet
expect( format( '%[p1]f' , 123 ) ).to.be( '10000' ) ;
expect( format( '%[p2]f' , 123 ) ).to.be( '12000' ) ;
expect( format( '%[p1]f' , 1/3 ) ).to.be( '0.3' ) ;
expect( format( '%[p2]f' , 1/3 ) ).to.be( '0.33' ) ;
expect( format( '%[p1]f' , 0.1 ) ).to.be( '0.1' ) ;
expect( format( '%[p2]f' , 0.1 ) ).to.be( '0.10' ) ;
*/
```
**Format.count() should count the number of arguments found**
```javascript
expect( format.count( 'blah blih blah' ) ).to.be( 0 ) ;
expect( format.count( 'blah blih %% blah' ) ).to.be( 0 ) ;
expect( format.count( '%i %s' ) ).to.be( 2 ) ;
expect( format.count( '%1i %1s' ) ).to.be( 1 ) ;
expect( format.count( '%5i' ) ).to.be( 5 ) ;
expect( format.count( '%[unexistant]F' ) ).to.be( 0 ) ;
expect( format.count( '%[unexistant:%a%a]F' ) ).to.be( 2 ) ;
```
**Format.hasFormatting() should return true if the string has formatting and thus need to be interpreted, or false otherwise**
```javascript
expect( format.hasFormatting( 'blah blih blah' ) ).to.be( false ) ;
expect( format.hasFormatting( 'blah blih %% blah' ) ).to.be( true ) ;
expect( format.hasFormatting( '%i %s' ) ).to.be( true ) ;
expect( format.hasFormatting( '%[unexistant]F' ) ).to.be( true ) ;
expect( format.hasFormatting( '%[unexistant:%a%a]F' ) ).to.be( true ) ;
```
**When using a filter object as the *this* context, the %[functionName]F format should use a custom function to format the input**
```javascript
var formatter = {
format: formatMethod ,
fn: {
fixed: function() { return 'f' ; } ,
double: function( str ) { return '' + str + str ; } ,
fxy: function( a , b ) { return '' + ( a * a + b ) ; }
}
} ;
expect( formatter.format( '%[fixed]F' ) ).to.be( 'f' ) ;
expect( formatter.format( '%[fixed]F%s%s%s' , 'A' , 'B' , 'C' ) ).to.be( 'fABC' ) ;
expect( formatter.format( '%s%[fxy:%a%a]F' , 'f(x,y)=' , 5 , 3 ) ).to.be( 'f(x,y)=28' ) ;
expect( formatter.format( '%s%[fxy:%+1a%-1a]F' , 'f(x,y)=' , 5 , 3 ) ).to.be( 'f(x,y)=14' ) ;
expect( formatter.format( '%[unexistant]F' ) ).to.be( '' ) ;
```
**'^' should add markup, defaulting to ansi markup**
```javascript
expect( format( 'this is ^^ a caret' ) ).to.be( 'this is ^ a caret' ) ;
expect( format( 'this is ^_underlined^: this is not' ) )
.to.be( 'this is ' + ansi.underline + 'underlined' + ansi.reset + ' this is not' + ansi.reset ) ;
expect( format( 'this is ^_underlined^ this is not' ) )
.to.be( 'this is ' + ansi.underline + 'underlined' + ansi.reset + ' this is not' + ansi.reset ) ;
expect( format( 'this is ^_underlined^:this is not' ) )
.to.be( 'this is ' + ansi.underline + 'underlined' + ansi.reset + 'this is not' + ansi.reset ) ;
expect( format( 'this is ^Bblue^: this is not' ) )
.to.be( 'this is ' + ansi.brightBlue + 'blue' + ansi.reset + ' this is not' + ansi.reset ) ;
expect( format( 'this is ^Bblue^ this is not' ) )
.to.be( 'this is ' + ansi.brightBlue + 'blue' + ansi.reset + ' this is not' + ansi.reset ) ;
```
**'^' markup: shift feature**
```javascript
expect( format( 'this background is ^#^bblue^ this is ^wwhite' ) )
.to.be( 'this background is ' + ansi.bgBlue + 'blue' + ansi.reset + ' this is ' + ansi.white + 'white' + ansi.reset ) ;
```
**Should expose a stand-alone markup only method**
```javascript
expect( string.markup( 'this is ^^ a caret' ) ).to.be( 'this is ^ a caret' ) ;
expect( string.markup( 'this is ^_underlined^: this is not' ) )
.to.be( 'this is ' + ansi.underline + 'underlined' + ansi.reset + ' this is not' + ansi.reset ) ;
expect( string.markup( 'this is ^_underlined^ this is not' ) )
.to.be( 'this is ' + ansi.underline + 'underlined' + ansi.reset + ' this is not' + ansi.reset ) ;
expect( string.markup( 'this is ^_underlined^:this is not' ) )
.to.be( 'this is ' + ansi.underline + 'underlined' + ansi.reset + 'this is not' + ansi.reset ) ;
expect( string.markup( 'this is ^Bblue^: this is not' ) )
.to.be( 'this is ' + ansi.brightBlue + 'blue' + ansi.reset + ' this is not' + ansi.reset ) ;
expect( string.markup( 'this is ^Bblue^ this is not' ) )
.to.be( 'this is ' + ansi.brightBlue + 'blue' + ansi.reset + ' this is not' + ansi.reset ) ;
// format syntax should be ignored
expect( string.markup( 'this is ^Bblue^ this is not %d' , 5 ) )
.to.be( 'this is ' + ansi.brightBlue + 'blue' + ansi.reset + ' this is not %d' + ansi.reset ) ;
```
**Should expose a stand-alone markup only method**
```javascript
var wwwFormatter = {
endingMarkupReset: true ,
markupReset: function( markupStack ) {
var str = '</span>'.repeat( markupStack.length ) ;
markupStack.length = 0 ;
return str ;
} ,
markup: {
":": function( markupStack ) {
var str = '</span>'.repeat( markupStack.length ) ;
markupStack.length = 0 ;
return str ;
} ,
" ": function( markupStack ) {
var str = '</span>'.repeat( markupStack.length ) ;
markupStack.length = 0 ;
return str + ' ' ;
} ,
"+": '<span style="font-weight:bold">' ,
"b": '<span style="color:blue">'
}
} ;
var markup = string.markupMethod.bind( wwwFormatter ) ;
var format = string.formatMethod.bind( wwwFormatter ) ;
expect( markup( 'this is ^^ a caret' ) ).to.be( 'this is ^ a caret' ) ;
expect( markup( 'this is ^+bold^: this is not' ) )
.to.be( 'this is <span style="font-weight:bold">bold</span> this is not' ) ;
expect( markup( 'this is ^+bold^ this is not' ) )
.to.be( 'this is <span style="font-weight:bold">bold</span> this is not' ) ;
expect( markup( 'this is ^+bold^:this is not' ) )
.to.be( 'this is <span style="font-weight:bold">bold</span>this is not' ) ;
expect( markup( 'this is ^b^+blue bold' ) )
.to.be( 'this is <span style="color:blue"><span style="font-weight:bold">blue bold</span></span>' ) ;
expect( format( 'this is ^b^+blue bold' ) )
.to.be( 'this is <span style="color:blue"><span style="font-weight:bold">blue bold</span></span>' ) ;
```
## Escape collection
**Escape.control() should escape control characters**
```javascript
expect( string.escape.control( 'Hello\n\t... world!' ) ).to.be( 'Hello\\n\\t... world!' ) ;
expect( string.escape.control( 'Hello\\n\\t... world!' ) ).to.be( 'Hello\\n\\t... world!' ) ;
expect( string.escape.control( 'Hello\\\n\\\t... world!' ) ).to.be( 'Hello\\\\n\\\\t... world!' ) ;
expect( string.escape.control( 'Hello\\\\n\\\\t... world!' ) ).to.be( 'Hello\\\\n\\\\t... world!' ) ;
expect( string.escape.control( 'Nasty\x00chars\x1bhere\x7f!' ) ).to.be( 'Nasty\\x00chars\\x1bhere\\x7f!' ) ;
```
**Escape.shellArg() should escape a string so that it will be suitable as a shell command's argument**
```javascript
//console.log( 'Shell arg:' , string.escape.shellArg( "Here's my shell's argument" ) ) ;
expect( string.escape.shellArg( "Here's my shell's argument" ) ).to.be( "'Here'\\''s my shell'\\''s argument'" ) ;
```
**Escape.jsSingleQuote() should escape a string so that it will be suitable as a JS string code**
```javascript
expect( string.escape.jsSingleQuote( "A string with 'single' quotes" ) ).to.be( "A string with \\'single\\' quotes" ) ;
expect( string.escape.jsSingleQuote( "A string with 'single' quotes\nand new\nlines" ) ).to.be( "A string with \\'single\\' quotes\\nand new\\nlines" ) ;
```
**Escape.jsDoubleQuote() should escape a string so that it will be suitable as a JS string code**
```javascript
expect( string.escape.jsDoubleQuote( 'A string with "double" quotes' ) ).to.be( 'A string with \\"double\\" quotes' ) ;
expect( string.escape.jsDoubleQuote( 'A string with "double" quotes\nand new\nlines' ) ).to.be( 'A string with \\"double\\" quotes\\nand new\\nlines' ) ;
```
**Escape.regExp() should escape a string so that it will be suitable as a literal string into a regular expression pattern**
```javascript
//console.log( 'String in RegExp:' , string.escape.regExp( "(This) {is} [my] ^$tring^... +doesn't+ *it*? |yes| \\no\\ /maybe/" ) ) ;
expect( string.escape.regExp( "(This) {is} [my] ^$tring^... +doesn't+ *it*? |yes| \\no\\ /maybe/" ) )
.to.be( "\\(This\\) \\{is\\} \\[my\\] \\^\\$tring\\^\\.\\.\\. \\+doesn't\\+ \\*it\\*\\? \\|yes\\| \\\\no\\\\ \\/maybe\\/" ) ;
```
**Escape.regExpReplacement() should escape a string so that it will be suitable as a literal string into a regular expression replacement**
```javascript
expect( string.escape.regExpReplacement( "$he love$ dollar$ $$$" ) ).to.be( "$$he love$$ dollar$$ $$$$$$" ) ;
expect(
'$he love$ dollar$ $$$'.replace(
new RegExp( string.escape.regExp( '$' ) , 'g' ) ,
string.escape.regExpReplacement( '$1' )
)
).to.be( "$1he love$1 dollar$1 $1$1$1" ) ;
```
**Escape.html() should escape a string so that it will be suitable as HTML content**
```javascript
//console.log( string.escape.html( "<This> isn't \"R&D\"" ) ) ;
expect( string.escape.html( "<This> isn't \"R&D\"" ) ).to.be( "<This> isn't \"R&D\"" ) ;
```
**Escape.htmlAttr() should escape a string so that it will be suitable as an HTML tag attribute's value**
```javascript
//console.log( string.escape.htmlAttr( "<This> isn't \"R&D\"" ) ) ;
expect( string.escape.htmlAttr( "<This> isn't \"R&D\"" ) ).to.be( "<This> isn't "R&D"" ) ;
```
**Escape.htmlSpecialChars() should escape all HTML special characters**
```javascript
//console.log( string.escape.htmlSpecialChars( "<This> isn't \"R&D\"" ) ) ;
expect( string.escape.htmlSpecialChars( "<This> isn't \"R&D\"" ) ).to.be( "<This> isn't "R&D"" ) ;
```
## Camel case
**.toCamelCase() should transform a string composed of alphanum - minus - underscore to a camelCase string**
```javascript
expect( string.toCamelCase( 'one-two-three' ) ).to.be( 'oneTwoThree' ) ;
expect( string.toCamelCase( 'one_two_three' ) ).to.be( 'oneTwoThree' ) ;
expect( string.toCamelCase( 'OnE-tWo_tHree' ) ).to.be( 'oneTwoThree' ) ;
expect( string.toCamelCase( 'ONE-TWO-THREE' ) ).to.be( 'oneTwoThree' ) ;
expect( string.toCamelCase( 'a-b-c' ) ).to.be( 'aBC' ) ;
```
**.toCamelCase() edge cases**
```javascript
expect( string.toCamelCase( '' ) ).to.be( '' ) ;
expect( string.toCamelCase() ).to.be( '' ) ;
expect( string.toCamelCase( 'u' ) ).to.be( 'u' ) ;
expect( string.toCamelCase( 'U' ) ).to.be( 'u' ) ;
expect( string.toCamelCase( 'U-b' ) ).to.be( 'uB' ) ;
expect( string.toCamelCase( 'U-' ) ).to.be( 'u' ) ;
expect( string.toCamelCase( '-U' ) ).to.be( 'u' ) ;
```
**.camelCaseToDashed() should transform a string composed of alphanum - minus - underscore to a camelCase string**
```javascript
expect( string.camelCaseToDashed( 'oneTwoThree' ) ).to.be( 'one-two-three' ) ;
expect( string.camelCaseToDashed( 'OneTwoThree' ) ).to.be( 'one-two-three' ) ;
expect( string.camelCaseToDashed( 'aBC' ) ).to.be( 'a-b-c' ) ;
```
## Latinize
**.latinize() should transform to regular latin letters without any accent**
```javascript
expect( string.latinize( 'éàèùâêîôûÂÊÎÔÛäëïöüÄËÏÖÜæÆŧøþßðđħł' ) )
.to.be( 'eaeuaeiouAEIOUaeiouAEIOUaeAEtothssdhdhl' ) ;
```
## Wordwrap
**.wordwrap() should wrap words**
```javascript
expect( string.wordwrap( 'one two three four five six seven' , 10 ) ).to.be( 'one two\nthree\nfour five\nsix seven' ) ;
expect( string.wordwrap( 'one two three four five six seven' , 10 , '<br />\n' ) ).to.be( 'one two<br />\nthree<br />\nfour five<br />\nsix seven' ) ;
expect( string.wordwrap( 'one two three four five six seven' , 10 , null ) ).to.eql( [ 'one two' , 'three' , 'four five' , 'six seven' ] ) ;
expect( string.wordwrap( 'one\ntwo three four five six seven' , 10 ) ).to.be( 'one\ntwo three\nfour five\nsix seven' ) ;
expect( string.wordwrap( ' one\ntwo three four five six seven' , 10 ) ).to.be( 'one\ntwo three\nfour five\nsix seven' ) ;
expect( string.wordwrap( ' one \ntwo three four five six seven' , 10 ) ).to.be( 'one\ntwo three\nfour five\nsix seven' ) ;
```
**.wordwrap() and surrogate pairs**
```javascript
expect( string.wordwrap( '𝌆𝌆𝌆 𝌆𝌆𝌆 𝌆𝌆𝌆𝌆𝌆 𝌆𝌆𝌆𝌆 𝌆𝌆𝌆𝌆 𝌆𝌆𝌆 𝌆𝌆𝌆𝌆𝌆' , 10 ) ).to.be( '𝌆𝌆𝌆 𝌆𝌆𝌆\n𝌆𝌆𝌆𝌆𝌆\n𝌆𝌆𝌆𝌆 𝌆𝌆𝌆𝌆\n𝌆𝌆𝌆 𝌆𝌆𝌆𝌆𝌆' ) ;
```
**.wordwrap() and fullwidth chars**
```javascript
expect( string.wordwrap( '備備 備備備 備備備備 備備' , 10 ) ).to.be( '備備\n備備備\n備備備備\n備備' ) ;
expect( string.wordwrap( '備備 備備 備 備備備備 備備' , 10 ) ).to.be( '備備 備備\n備\n備備備備\n備備' ) ;
expect( string.wordwrap( '備備 備備 備 備 備 備備 備備備' , 10 ) ).to.be( '備備 備備\n備 備 備\n備備\n備備備' ) ;
```
**.wordwrap() and french typography rules with '!', '?', ':' and ';'**
```javascript
expect( string.wordwrap( 'un ! deux ? trois : quatre ; cinq !' , 10 ) ).to.be( 'un !\ndeux ?\ntrois :\nquatre ;\ncinq !' ) ;
```
## inspect()
**Should inspect a variable with default options accordingly**
```javascript
var MyClass = function MyClass() {
this.variable = 1 ;
} ;
MyClass.prototype.report = function report() { console.log( 'Variable value:' , this.variable ) ; } ;
MyClass.staticFunc = function staticFunc() { console.log( 'Static function.' ) ; } ;
var sparseArray = [] ;
sparseArray[ 3 ] = 'three' ;
sparseArray[ 10 ] = 'ten' ;
sparseArray[ 20 ] = 'twenty' ;
sparseArray.customProperty = 'customProperty' ;
var object = {
a: 'A' ,
b: 2 ,
str: 'Woot\nWoot\rWoot\tWoot' ,
sub: {
u: undefined ,
n: null ,
t: true ,
f: false
} ,
emptyString: '' ,
emptyObject: {} ,
list: [ 'one','two','three' ] ,
emptyList: [] ,
sparseArray: sparseArray ,
hello: function hello() { console.log( 'Hello!' ) ; } ,
anonymous: function() { console.log( 'anonymous...' ) ; } ,
class: MyClass ,
instance: new MyClass() ,
buf: new Buffer( 'This is a buffer!' )
} ;
object.sub.circular = object ;
Object.defineProperties( object , {
c: { value: '3' } ,
d: {
get: function() { throw new Error( 'Should not be called by the test' ) ; } ,
set: function( value ) {}
}
} ) ;
//console.log( '>>>>>' , string.escape.control( string.inspect( object ) ) ) ;
//console.log( string.inspect( { style: 'color' } , object ) ) ;
var actual = string.inspect( object ) ;
var expected = '<Object> <object> {\n a: "A" <string>(1)\n b: 2 <number>\n str: "Woot\\nWoot\\rWoot\\tWoot" <string>(19)\n sub: <Object> <object> {\n u: undefined\n n: null\n t: true\n f: false\n circular: <Object> <object> [circular]\n }\n emptyString: "" <string>(0)\n emptyObject: <Object> <object> {}\n list: <Array>(3) <object> {\n [0] "one" <string>(3)\n [1] "two" <string>(3)\n [2] "three" <string>(5)\n length: 3 <number> <-conf -enum>\n }\n emptyList: <Array>(0) <object> {\n length: 0 <number> <-conf -enum>\n }\n sparseArray: <Array>(21) <object> {\n [3] "three" <string>(5)\n [10] "ten" <string>(3)\n [20] "twenty" <string>(6)\n length: 21 <number> <-conf -enum>\n customProperty: "customProperty" <string>(14)\n }\n hello: <Function> hello(0) <function>\n anonymous: <Function> anonymous(0) <function>\n class: <Function> MyClass(0) <function>\n instance: <MyClass> <object> {\n variable: 1 <number>\n }\n buf: <Buffer 54 68 69 73 20 69 73 20 61 20 62 75 66 66 65 72 21> <Buffer>(17)\n c: "3" <string>(1) <-conf -enum -w>\n d: <getter/setter> {\n get: <Function> get(0) <function>\n set: <Function> set(1) <function>\n }\n}\n' ;
//console.log( '\n' + expected + '\n\n' + actual + '\n\n' ) ;
expect( actual ).to.be( expected ) ;
//console.log( string.inspect( { style: 'color' } , object ) ) ;
```
**Should pass the Array circular references bug**
```javascript
var array = [ [ 1 ] ] ;
expect( string.inspect( array ) ).to.be( '<Array>(1) <object> {\n [0] <Array>(1) <object> {\n [0] 1 <number>\n length: 1 <number> <-conf -enum>\n }\n length: 1 <number> <-conf -enum>\n}\n' ) ;
```
**Should inspect object with no constructor**
```javascript
expect( string.inspect( Object.assign( Object.create( null ) , { a: 1, b: 2 } ) ) ).to.be( '<(no constructor)> <object> {\n a: 1 <number>\n b: 2 <number>\n}\n' ) ;
```
## Title case
**Basic .toTitleCase() usages**
```javascript
expect( string.toTitleCase( 'bob bill booo électron hétérogénéité ALLCAPS McDowell jean-michel' ) )
.to.be( 'Bob Bill Booo Électron Hétérogénéité ALLCAPS McDowell Jean-Michel' ) ;
expect( string.toTitleCase( 'bob bill booo électron hétérogénéité ALLCAPS McDowell jean-michel' , { zealous: true } ) )
.to.be( 'Bob Bill Booo Électron Hétérogénéité Allcaps Mcdowell Jean-Michel' ) ;
expect( string.toTitleCase( 'bob bill booo électron hétérogénéité ALLCAPS McDowell jean-michel' , { zealous: true , preserveAllCaps: true } ) )
.to.be( 'Bob Bill Booo Électron Hétérogénéité ALLCAPS Mcdowell Jean-Michel' ) ;
```
## Misc
**.resize()**
```javascript
expect( string.resize( 'bobby' , 3 ) ).to.be( 'bob' ) ;
expect( string.resize( 'bobby' , 5 ) ).to.be( 'bobby' ) ;
expect( string.resize( 'bobby' , 8 ) ).to.be( 'bobby ' ) ;
```
**.occurenceCount()**
```javascript
expect( string.occurenceCount( '' , '' ) ).to.be( 0 ) ;
expect( string.occurenceCount( 'three' , '' ) ).to.be( 0 ) ;
expect( string.occurenceCount( '' , 'o' ) ).to.be( 0 ) ;
expect( string.occurenceCount( '' , 'omg' ) ).to.be( 0 ) ;
expect( string.occurenceCount( 'three' , 'o' ) ).to.be( 0 ) ;
expect( string.occurenceCount( 'o' , 'o' ) ).to.be( 1 ) ;
expect( string.occurenceCount( 'ooo' , 'o' ) ).to.be( 3 ) ;
expect( string.occurenceCount( 'ooo' , 'oo' ) ).to.be( 1 ) ;
expect( string.occurenceCount( 'aooo' , 'oo' ) ).to.be( 1 ) ;
expect( string.occurenceCount( 'aoooo' , 'oo' ) ).to.be( 2 ) ;
expect( string.occurenceCount( 'one two three four' , 'o' ) ).to.be( 3 ) ;
expect( string.occurenceCount( 'one one one' , 'one' ) ).to.be( 3 ) ;
expect( string.occurenceCount( 'oneoneone' , 'one' ) ).to.be( 3 ) ;
```
## Unicode
**Unicode.length() should report correctly the length of a string**
```javascript
expect( string.unicode.length( '' ) ).to.be( 0 ) ;
expect( string.unicode.length( 'a' ) ).to.be( 1 ) ;
expect( string.unicode.length( 'abc' ) ).to.be( 3 ) ;
expect( string.unicode.length( '\x1b[' ) ).to.be( 2 ) ;
expect( string.unicode.length( '𝌆' ) ).to.be( 1 ) ;
expect( string.unicode.length( 'a𝌆' ) ).to.be( 2 ) ;
expect( string.unicode.length( 'a𝌆a𝌆a' ) ).to.be( 5 ) ;
expect( string.unicode.length( 'é𝌆é𝌆é' ) ).to.be( 5 ) ;
expect( string.unicode.length( '䷆䷆' ) ).to.be( 2 ) ;
expect( string.unicode.length( '備' ) ).to.be( 1 ) ;
expect( string.unicode.length( '備備' ) ).to.be( 2 ) ;
expect( string.unicode.length( '備-備' ) ).to.be( 3 ) ;
```
**Unicode.toArray() should produce an array of character**
```javascript
expect( string.unicode.toArray( '' ) ).to.eql( [] ) ;
expect( string.unicode.toArray( 'a' ) ).to.eql( [ 'a' ] ) ;
expect( string.unicode.toArray( 'abc' ) ).to.eql( [ 'a' , 'b' , 'c' ] ) ;
expect( string.unicode.toArray( '\x1b[' ) ).to.eql( [ '\x1b' , '[' ] ) ;
expect( string.unicode.toArray( '𝌆' ) ).to.eql( [ '𝌆' ] ) ;
expect( string.unicode.toArray( 'a𝌆' ) ).to.eql( [ 'a' , '𝌆' ] ) ;
expect( string.unicode.toArray( 'a𝌆a𝌆a' ) ).to.eql( [ 'a' , '𝌆' , 'a' , '𝌆' , 'a' ] ) ;
expect( string.unicode.toArray( 'é𝌆é𝌆é' ) ).to.eql( [ 'é' , '𝌆' , 'é' , '𝌆' , 'é' ] ) ;
expect( string.unicode.toArray( '䷆䷆' ) ).to.eql( [ '䷆' , '䷆' ] ) ;
expect( string.unicode.toArray( '備' ) ).to.eql( [ '備' ] ) ;
expect( string.unicode.toArray( '備備' ) ).to.eql( [ '備' , '備' ] ) ;
expect( string.unicode.toArray( '備-備' ) ).to.eql( [ '備' , '-' , '備' ] ) ;
```
**Unicode.surrogatePair() should return 0 for single char, 1 for leading surrogate, -1 for trailing surrogate**
```javascript
expect( string.unicode.surrogatePair( 'a' ) ).to.be( 0 ) ;
expect( '𝌆'.length ).to.be( 2 ) ;
expect( string.unicode.surrogatePair( '𝌆'[0] ) ).to.be( 1 ) ;
expect( string.unicode.surrogatePair( '𝌆'[1] ) ).to.be( -1 ) ;
expect( '備'.length ).to.be( 2 ) ;
expect( string.unicode.surrogatePair( '備'[0] ) ).to.be( 1 ) ;
expect( string.unicode.surrogatePair( '備'[1] ) ).to.be( -1 ) ;
// Can be wide or not, but expressed in only 1 code unit
expect( '䷆'.length ).to.be( 1 ) ;
expect( string.unicode.surrogatePair( '䷆'[0] ) ).to.be( 0 ) ;
// expect( string.unicode.surrogatePair( '䷆'[1] ) ).to.be( undefined ) ;
```
**Unicode.isFullWidth() should return true if the char is full-width**
```javascript
expect( string.unicode.isFullWidth( 'a' ) ).to.be( false ) ;
expect( string.unicode.isFullWidth( '@' ) ).to.be( true ) ;
expect( string.unicode.isFullWidth( '𝌆' ) ).to.be( false ) ;
expect( string.unicode.isFullWidth( '備' ) ).to.be( true ) ;
expect( string.unicode.isFullWidth( '䷆' ) ).to.be( false ) ;
```
**.toFullWidth() should transform a character to its full-width variant, if it exist**
```javascript
expect( string.unicode.toFullWidth( '@' ) ).to.be( '@' ) ;
expect( string.unicode.toFullWidth( 'é' ) ).to.be( 'é' ) ;
```
**.width() should return the width of a string when displayed on a terminal or a monospace font**
```javascript
expect( string.unicode.width( 'aé@à' ) ).to.be( 4 ) ;
expect( string.unicode.width( 'aé@à' ) ).to.be( 5 ) ;
```