v/vlib/builtin/string_test.v

955 lines
19 KiB
V
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import strings
// Copyright (c) 2019-2022 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
struct Foo {
bar int
mut:
str string
}
fn test_add() {
mut a := 'a'
a += 'b'
assert a == ('ab')
a = 'a'
for i := 1; i < 1000; i++ {
a += 'b'
}
assert a.len == 1000
assert a.ends_with('bbbbb')
a += '123'
assert a.ends_with('3')
}
fn test_ends_with() {
a := 'browser.v'
assert a.ends_with('.v')
s := 'V Programming Language'
assert s.ends_with('guage') == true
assert s.ends_with('Language') == true
assert s.ends_with('Programming Language') == true
assert s.ends_with('V') == false
}
fn test_between() {
s := 'hello [man] how you doing'
assert s.find_between('[', ']') == 'man'
}
fn test_compare() {
a := 'Music'
b := 'src'
assert b >= a
}
fn test_lt() {
a := ''
b := 'a'
c := 'a'
d := 'b'
e := 'aa'
f := 'ab'
assert a < b
assert !(b < c)
assert c < d
assert !(d < e)
assert c < e
assert e < f
}
fn test_ge() {
a := 'aa'
b := 'aa'
c := 'ab'
d := 'abc'
e := 'aaa'
assert b >= a
assert c >= b
assert d >= c
assert !(c >= d)
assert e >= a
}
fn test_compare_strings() {
a := 'aa'
b := 'aa'
c := 'ab'
d := 'abc'
e := 'aaa'
assert compare_strings(a, b) == 0
assert compare_strings(b, c) == -1
assert compare_strings(c, d) == -1
assert compare_strings(d, e) == 1
assert compare_strings(a, e) == -1
assert compare_strings(e, a) == 1
}
fn test_sort() {
mut vals := [
'arr',
'an',
'a',
'any',
]
len := vals.len
vals.sort()
assert len == vals.len
assert vals[0] == 'a'
assert vals[1] == 'an'
assert vals[2] == 'any'
assert vals[3] == 'arr'
}
fn test_sort_reverse() {
mut vals := [
'arr',
'an',
'a',
'any',
]
len := vals.len
vals.sort(b > a)
assert len == vals.len
assert vals[0] == 'a'
assert vals[1] == 'an'
assert vals[2] == 'any'
assert vals[3] == 'arr'
}
fn test_split_nth() {
a := '1,2,3'
assert a.split(',').len == 3
assert a.split_nth(',', -1).len == 3
assert a.split_nth(',', 0).len == 3
assert a.split_nth(',', 1).len == 1
assert a.split_nth(',', 2).len == 2
assert a.split_nth(',', 10).len == 3
b := '1::2::3'
assert b.split('::').len == 3
assert b.split_nth('::', -1).len == 3
assert b.split_nth('::', 0).len == 3
assert b.split_nth('::', 1).len == 1
assert b.split_nth('::', 2).len == 2
assert b.split_nth('::', 10).len == 3
c := 'ABCDEF'
println(c.split('').len)
assert c.split('').len == 6
assert c.split_nth('', 3).len == 3
assert c.split_nth('BC', -1).len == 2
d := ','
assert d.split(',').len == 2
assert d.split_nth('', 3).len == 1
assert d.split_nth(',', -1).len == 2
assert d.split_nth(',', 3).len == 2
e := ',,,0,,,,,a,,b,'
assert e.split(',,').len == 5
assert e.split_nth(',,', 3).len == 3
assert e.split_nth(',', -1).len == 12
assert e.split_nth(',', 3).len == 3
}
fn test_split_nth_values() {
line := 'CMD=eprintln(phase=1)'
a0 := line.split_nth('=', 0)
assert a0.len == 3
assert a0[0] == 'CMD'
assert a0[1] == 'eprintln(phase'
assert a0[2] == '1)'
a1 := line.split_nth('=', 1)
assert a1.len == 1
assert a1[0] == 'CMD=eprintln(phase=1)'
a2 := line.split_nth('=', 2)
assert a2.len == 2
assert a2[0] == 'CMD'
assert a2[1] == 'eprintln(phase=1)'
a3 := line.split_nth('=', 3)
assert a3.len == 3
assert a3[0] == 'CMD'
assert a3[1] == 'eprintln(phase'
assert a3[2] == '1)'
a4 := line.split_nth('=', 4)
assert a4.len == 3
assert a4[0] == 'CMD'
assert a4[1] == 'eprintln(phase'
assert a4[2] == '1)'
}
fn test_split() {
mut s := 'volt/twitch.v:34'
mut vals := s.split(':')
assert vals.len == 2
assert vals[0] == 'volt/twitch.v'
assert vals[1] == '34'
// /////////
s = '2018-01-01z13:01:02'
vals = s.split('z')
assert vals.len == 2
assert vals[0] == '2018-01-01'
assert vals[1] == '13:01:02'
// //////////
s = '4627a862c3dec29fb3182a06b8965e0025759e18___1530207969___blue'
vals = s.split('___')
assert vals.len == 3
assert vals[0] == '4627a862c3dec29fb3182a06b8965e0025759e18'
assert vals[1] == '1530207969'
assert vals[2] == 'blue'
// /////////
s = 'lalala'
vals = s.split('a')
assert vals.len == 4
assert vals[0] == 'l'
assert vals[1] == 'l'
assert vals[2] == 'l'
assert vals[3] == ''
// /////////
s = 'awesome'
a := s.split('')
assert a.len == 7
assert a[0] == 'a'
assert a[1] == 'w'
assert a[2] == 'e'
assert a[3] == 's'
assert a[4] == 'o'
assert a[5] == 'm'
assert a[6] == 'e'
// /////////
s = 'wavy turquoise bags'
vals = s.split(' bags')
assert vals.len == 2
assert vals[0] == 'wavy turquoise'
assert vals[1] == ''
}
fn test_split_any() {
assert 'ABC'.split_any('') == ['A', 'B', 'C']
assert ''.split_any(' ') == []
assert ' '.split_any(' ') == ['']
assert ' '.split_any(' ') == ['', '']
assert 'Ciao come stai? '.split_any(' ') == ['Ciao', 'come', 'stai?']
assert 'Ciao+come*stai? '.split_any('+*') == ['Ciao', 'come', 'stai? ']
assert 'Ciao+come*stai? '.split_any('+* ') == ['Ciao', 'come', 'stai?']
assert 'first row\nsecond row'.split_any(' \n') == ['first', 'row', 'second', 'row']
}
fn test_trim_space() {
a := ' a '
assert a.trim_space() == 'a'
code := '
fn main() {
println(2)
}
'
code_clean := 'fn main() {
println(2)
}'
assert code.trim_space() == code_clean
}
fn test_join() {
mut strings := ['a', 'b', 'c']
mut s := strings.join(' ')
assert s == 'a b c'
strings = [
'one
two ',
'three!
four!',
]
s = strings.join(' ')
assert s.contains('one') && s.contains('two ') && s.contains('four')
empty := []string{len: 0}
assert empty.join('A') == ''
}
fn test_clone() {
mut a := 'a'
a += 'a'
a += 'a'
b := a
c := a.clone()
assert c == a
assert c == 'aaa'
assert b == 'aaa'
}
fn test_replace() {
a := 'hello man!'
mut b := a.replace('man', 'world')
assert b == ('hello world!')
b = b.replace('!', '')
assert b == ('hello world')
b = b.replace('h', 'H')
assert b == ('Hello world')
b = b.replace('foo', 'bar')
assert b == ('Hello world')
s := 'hey man how are you'
assert s.replace('man ', '') == 'hey how are you'
lol := 'lol lol lol'
assert lol.replace('lol', 'LOL') == 'LOL LOL LOL'
b = 'oneBtwoBBthree'
assert b.replace('B', '') == 'onetwothree'
b = '*charptr'
assert b.replace('charptr', 'byteptr') == '*byteptr'
c := 'abc'
assert c.replace('', '-') == c
v := 'a b c d'
assert v.replace(' ', ' ') == 'a b c d'
}
fn test_replace_each() {
s := 'hello man man :)'
q := s.replace_each([
'man',
'dude',
'hello',
'hey',
])
assert q == 'hey dude dude :)'
bb := '[b]bold[/b] [code]code[/code]'
assert bb.replace_each([
'[b]',
'<b>',
'[/b]',
'</b>',
'[code]',
'<code>',
'[/code]',
'</code>',
]) == '<b>bold</b> <code>code</code>'
bb2 := '[b]cool[/b]'
assert bb2.replace_each([
'[b]',
'<b>',
'[/b]',
'</b>',
]) == '<b>cool</b>'
t := 'aaaaaaaa'
y := t.replace_each([
'aa',
'b',
])
assert y == 'bbbb'
s2 := 'hello_world hello'
assert s2.replace_each(['hello_world', 'aaa', 'hello', 'bbb']) == 'aaa bbb'
}
fn test_itoa() {
num := 777
assert num.str() == '777'
big := 7779998
assert big.str() == '7779998'
a := 3
assert a.str() == '3'
b := 5555
assert b.str() == '5555'
zero := 0
assert zero.str() == '0'
neg := -7
assert neg.str() == '-7'
}
fn test_reassign() {
a := 'hi'
mut b := a
b += '!'
assert a == 'hi'
assert b == 'hi!'
}
fn test_runes() {
s := 'привет'
assert s.len == 12
s2 := 'privet'
assert s2.len == 6
u := s.runes()
assert u.len == 6
assert s2.substr(1, 4).len == 3
assert s2.substr(1, 4) == 'riv'
assert s2[1..4].len == 3
assert s2[1..4] == 'riv'
assert s2[..4].len == 4
assert s2[..4] == 'priv'
assert s2[2..].len == 4
assert s2[2..] == 'ivet'
assert u[1..4].string().len == 6
assert u[1..4].string() == 'рив'
assert s2.substr(1, 2) == 'r'
assert u[1..2].string() == 'р'
assert s2.runes()[1] == `r`
assert u[1] == `р`
first := u[0]
last := u[u.len - 1]
assert first.str().len == 2
assert last.str().len == 2
}
fn test_contains() {
s := 'view.v'
assert s.contains('vi')
assert !s.contains('random')
assert ''.contains('')
assert 'abc'.contains('')
}
fn test_contains_any() {
assert !'team'.contains_any('i')
assert 'fail'.contains_any('ui')
assert 'ure'.contains_any('ui')
assert 'failure'.contains_any('ui')
assert !'foo'.contains_any('')
assert !''.contains_any('')
}
fn test_contains_any_substr() {
s := 'Some random text'
assert s.contains_any_substr(['false', 'not', 'rand'])
assert !s.contains_any_substr(['ABC', 'invalid'])
assert ''.contains_any_substr([])
assert 'abc'.contains_any_substr([''])
}
fn test_arr_contains() {
a := ['a', 'b', 'c']
assert a.contains('b')
ints := [1, 2, 3]
assert ints.contains(2)
}
fn test_to_num() {
s := '7'
assert s.int() == 7
assert s.byte() == 7
assert s.u64() == 7
f := '71.5 hasdf'
// QTODO
assert f.f32() == 71.5
vals := ['9']
assert vals[0].int() == 9
big := '93993993939322'
assert big.u64() == 93993993939322
assert big.i64() == 93993993939322
}
fn test_inter_format_string() {
float_num := 1.52345
float_num_string := '-${float_num:.3f}-'
assert float_num_string == '-1.523-'
int_num := 7
int_num_string := '-${int_num:03d}-'
assert int_num_string == '-007-'
ch := `a`
ch_string := '-${ch:c}-'
assert ch_string == '-a-'
hex_n := 192
hex_n_string := '-${hex_n:x}-'
assert hex_n_string == '-c0-'
oct_n := 192
oct_n_string := '-${oct_n:o}-'
assert oct_n_string == '-300-'
str := 'abc'
str_string := '-${str:s}-'
assert str_string == '-abc-'
}
fn test_hash() {
s := '10000'
assert s.hash() == 46730161
s2 := '24640'
assert s2.hash() == 47778736
s3 := 'Content-Type'
assert s3.hash() == 949037134
s4 := 'bad_key'
assert s4.hash() == -346636507
s5 := '24640'
// From a map collision test
assert s5.hash() % ((1 << 20) - 1) == s.hash() % ((1 << 20) - 1)
assert s5.hash() % ((1 << 20) - 1) == 592861
}
fn test_trim() {
assert 'banana'.trim('bna') == ''
assert 'abc'.trim('ac') == 'b'
assert 'aaabccc'.trim('ac') == 'b'
}
fn test_trim_left() {
mut s := 'module main'
assert s.trim_left(' ') == 'module main'
s = ' module main'
assert s.trim_left(' ') == 'module main'
// test cutset
s = 'banana'
assert s.trim_left('ba') == 'nana'
assert s.trim_left('ban') == ''
}
fn test_trim_right() {
mut s := 'module main'
assert s.trim_right(' ') == 'module main'
s = 'module main '
assert s.trim_right(' ') == 'module main'
// test cutset
s = 'banana'
assert s.trim_right('na') == 'b'
assert s.trim_right('ban') == ''
}
fn test_all_before() {
s := 'fn hello fn'
assert s.all_before(' ') == 'fn'
assert s.all_before('2') == s
assert s.all_before('') == s
}
fn test_all_before_last() {
s := 'fn hello fn'
assert s.all_before_last(' ') == 'fn hello'
assert s.all_before_last('2') == s
assert s.all_before_last('') == s
}
fn test_all_after() {
s := 'fn hello'
assert s.all_after('fn ') == 'hello'
assert s.all_after('test') == s
assert s.all_after('') == s
assert s.after('e') == 'llo'
x := s.after('e')
assert x == 'llo'
}
fn test_reverse() {
assert 'hello'.reverse() == 'olleh'
assert ''.reverse() == ''
assert 'a'.reverse() == 'a'
}
fn test_bytes_to_string() {
mut buf := vcalloc(10)
unsafe {
buf[0] = `h`
buf[1] = `e`
buf[2] = `l`
buf[3] = `l`
buf[4] = `o`
}
assert unsafe { buf.vstring() } == 'hello'
assert unsafe { buf.vstring_with_len(2) } == 'he'
bytes := [byte(`h`), `e`, `l`, `l`, `o`]
assert bytes.bytestr() == 'hello'
}
fn test_charptr() {
foo := &char('VLANG'.str)
println(typeof(foo).name)
assert typeof(foo).name == '&char'
assert unsafe { foo.vstring() } == 'VLANG'
assert unsafe { foo.vstring_with_len(3) } == 'VLA'
}
fn test_count() {
assert ''.count('') == 0
assert ''.count('a') == 0
assert 'a'.count('') == 0
assert 'aa'.count('a') == 2
assert 'aa'.count('aa') == 1
assert 'aabbaa'.count('aa') == 2
assert 'bbaabb'.count('aa') == 1
}
fn test_lower() {
mut s := 'A'
assert !s.is_lower()
assert s.to_lower() == 'a'
assert s.to_lower().len == 1
s = 'HELLO'
assert !s.is_lower()
assert s.to_lower() == 'hello'
assert s.to_lower().len == 5
s = 'Aloha'
assert !s.is_lower()
assert s.to_lower() == 'aloha'
s = 'Have A nice Day!'
assert !s.is_lower()
assert s.to_lower() == 'have a nice day!'
s = 'hi'
assert s.is_lower()
assert s.to_lower() == 'hi'
assert 'aloha!'[0] == `a`
assert 'aloha!'[5] == `!`
}
fn test_upper() {
mut s := 'a'
assert !s.is_upper()
assert s.to_upper() == 'A'
assert s.to_upper().len == 1
s = 'hello'
assert !s.is_upper()
assert s.to_upper() == 'HELLO'
assert s.to_upper().len == 5
s = 'Aloha'
assert !s.is_upper()
assert s.to_upper() == 'ALOHA'
s = 'have a nice day!'
assert !s.is_upper()
assert s.to_upper() == 'HAVE A NICE DAY!'
s = 'HI'
assert s.is_upper()
assert s.to_upper() == 'HI'
}
fn test_capitalize() {
mut s := 'hello'
assert !s.is_capital()
assert s.capitalize() == 'Hello'
s = 'test'
assert !s.is_capital()
assert s.capitalize() == 'Test'
s = 'i am ray'
assert !s.is_capital()
assert s.capitalize() == 'I am ray'
s = ''
assert !s.is_capital()
assert s.capitalize() == ''
s = 'TEST IT'
assert !s.is_capital()
assert s.capitalize() == 'TEST IT'
s = 'Test it'
assert s.is_capital()
assert s.capitalize() == 'Test it'
assert 'GameMission_t'.capitalize() == 'GameMission_t'
}
fn test_title() {
mut s := 'hello world'
assert !s.is_title()
assert s.title() == 'Hello World'
s = 'HELLO WORLD'
assert !s.is_title()
assert s.title() == 'HELLO WORLD'
s = 'Hello World'
assert s.is_title()
assert s.title() == 'Hello World'
}
fn test_for_loop() {
mut i := 0
s := 'abcd'
for c in s {
assert c == s[i]
i++
}
}
fn test_for_loop_two() {
s := 'abcd'
for i, c in s {
assert c == s[i]
}
}
fn test_quote() {
a := `'`
println('testing double quotes')
b := 'hi'
assert b == 'hi'
assert a.str() == "'"
}
fn test_limit() {
s := 'hello'
assert s.limit(2) == 'he'
assert s.limit(9) == s
assert s.limit(0) == ''
// assert s.limit(-1) == ''
}
fn test_repeat() {
s1 := 'V! '
assert s1.repeat(5) == 'V! V! V! V! V! '
assert s1.repeat(1) == s1
assert s1.repeat(0) == ''
s2 := ''
assert s2.repeat(5) == s2
assert s2.repeat(1) == s2
assert s2.repeat(0) == s2
// TODO Add test for negative values
}
fn test_starts_with() {
s := 'V Programming Language'
assert s.starts_with('V') == true
assert s.starts_with('V Programming') == true
assert s.starts_with('Language') == false
}
fn test_starts_with_capital() {
assert 'A sentence'.starts_with_capital()
assert 'A paragraph. It also does.'.starts_with_capital()
assert ''.starts_with_capital() == false
assert 'no'.starts_with_capital() == false
assert ' No'.starts_with_capital() == false
}
fn test_trim_prefix() {
s := 'V Programming Language'
assert s.trim_prefix('V ') == 'Programming Language'
assert s.trim_prefix('V Programming ') == 'Language'
assert s.trim_prefix('Language') == s
s2 := 'TestTestTest'
assert s2.trim_prefix('Test') == 'TestTest'
assert s2.trim_prefix('TestTest') == 'Test'
s3 := '123Test123Test'
assert s3.trim_prefix('123') == 'Test123Test'
assert s3.trim_prefix('123Test') == '123Test'
}
fn test_trim_suffix() {
s := 'V Programming Language'
assert s.trim_suffix(' Language') == 'V Programming'
assert s.trim_suffix(' Programming Language') == 'V'
assert s.trim_suffix('V') == s
s2 := 'TestTestTest'
assert s2.trim_suffix('Test') == 'TestTest'
assert s2.trim_suffix('TestTest') == 'Test'
s3 := '123Test123Test'
assert s3.trim_suffix('123') == s3
assert s3.trim_suffix('123Test') == '123Test'
}
fn test_raw() {
raw := r'raw\nstring'
lines := raw.split('\n')
println(lines)
assert lines.len == 1
println('raw string: "$raw"')
raw2 := r'Hello V\0'
assert raw2[7] == `\\`
assert raw2[8] == `0`
raw3 := r'Hello V\x00'
assert raw3[7] == `\\`
assert raw3[8] == `x`
assert raw3[9] == `0`
assert raw3[10] == `0`
}
fn test_raw_with_quotes() {
raw := r"some'" + r'"thing' // " should be escaped in the generated C code
assert raw[0] == `s`
assert raw[5] == `"`
assert raw[6] == `t`
}
fn test_escape() {
a := 10
println("\"$a")
assert "\"$a" == '"10'
}
fn test_atoi() {
assert '234232'.int() == 234232
assert '-9009'.int() == -9009
assert '0'.int() == 0
for n in -10000 .. 100000 {
s := n.str()
assert s.int() == n
}
}
fn test_raw_inter() {
world := 'world'
println(world)
s := r'hello\n$world'
assert s == r'hello\n$world'
assert s.contains('$')
}
fn test_c_r() {
// This used to break because of r'' and c''
c := 42
println('$c')
r := 50
println('$r')
}
fn test_inter_before_comptime_if() {
s := '123'
// This used to break ('123 $....')
$if linux {
println(s)
}
assert s == '123'
}
fn test_double_quote_inter() {
a := 1
b := 2
println('$a $b')
assert '$a $b' == '1 2'
assert '$a $b' == '1 2'
}
fn foo(b byte) byte {
return b - 10
}
fn filter(b byte) bool {
return b != `a`
}
fn test_split_into_lines() {
line_content := 'Line'
text_crlf := '$line_content\r\n$line_content\r\n$line_content'
lines_crlf := text_crlf.split_into_lines()
assert lines_crlf.len == 3
for line in lines_crlf {
assert line == line_content
}
text_lf := '$line_content\n$line_content\n$line_content'
lines_lf := text_lf.split_into_lines()
assert lines_lf.len == 3
for line in lines_lf {
assert line == line_content
}
}
fn test_string_literal_with_backslash() {
a := 'HelloWorld'
assert a == 'HelloWorld'
b := 'OneTwoThree'
assert b == 'OneTwoThree'
}
/*
type MyString = string
fn test_string_alias() {
s := MyString('hi')
ss := s + '!'
}
*/
// sort an array of structs, by their string field values
struct Ka {
s string
i int
}
fn test_sorter() {
mut arr := [
Ka{
s: 'bbb'
i: 100
},
Ka{
s: 'aaa'
i: 101
},
Ka{
s: 'ccc'
i: 102
},
]
cmp := fn (a &Ka, b &Ka) int {
return compare_strings(a.s, b.s)
}
arr.sort_with_compare(cmp)
assert arr[0].s == 'aaa'
assert arr[0].i == 101
assert arr[1].s == 'bbb'
assert arr[1].i == 100
assert arr[2].s == 'ccc'
assert arr[2].i == 102
}
fn test_fields() {
assert 'a bcde'.fields() == ['a', 'bcde']
assert ' sss \t ssss '.fields() == ['sss', 'ssss']
assert '\n xyz \t abc def'.fields() == ['xyz', 'abc', 'def']
assert 'hello'.fields() == ['hello']
assert ''.fields() == []
}
fn test_interpolation_after_quoted_variable_still_works() {
rr := 'abc'
tt := 'xyz'
// Basic interpolation, no internal quotes
yy := 'Replacing $rr with $tt'
assert yy == 'Replacing abc with xyz'
// Interpolation after quoted variable ending with 'r'quote
// that may be mistaken with the start of a raw string,
// ensure that it is not.
ss := 'Replacing "$rr" with "$tt"'
assert ss == 'Replacing "abc" with "xyz"'
zz := "Replacing '$rr' with '$tt'"
assert zz == "Replacing 'abc' with 'xyz'"
// Interpolation after quoted variable ending with 'c'quote
// may be mistaken with the start of a c string, so
// check it is not.
cc := 'abc'
ccc := "Replacing '$cc' with '$tt'"
assert ccc == "Replacing 'abc' with 'xyz'"
cccq := 'Replacing "$cc" with "$tt"'
assert cccq == 'Replacing "abc" with "xyz"'
}
fn test_emoji_to_runes() {
x := '👋'
assert x.runes()[0] == `👋`
}
fn test_string_to_rune() {
x := 'Hello World 👋'
assert x.runes().len == 13
}
fn test_index_any() {
x := 'abcdefghij'
assert x.index_any('ef') == 4
assert x.index_any('fe') == 4
}
fn test_string_f64() {
assert ''.f64() == 0
assert '123'.f64() == 123
assert '-123'.f64() == -123
assert '-123.456'.f64() == -123.456
}
const f32_epsilon = 0.0000000001
fn test_string_f32() {
assert ''.f32() - 0 <= f32_epsilon
assert '123'.f32() - 123 < f32_epsilon
assert '-123'.f32() - (-123) < f32_epsilon
assert '-123.456'.f32() - (-123.456) <= f32_epsilon
}