v/vlib/v/tests/interface_test.v

466 lines
9.0 KiB
V

struct Dog {
breed string
}
struct Cat {
mut:
breed string
}
fn new_cat(breed string) Cat {
return Cat{breed}
}
fn (c &Cat) name() string {
if c.breed != '' {
assert c.breed == 'Persian'
}
return 'Cat'
}
fn (c &Cat) speak(s string) {
if c.breed != '' {
assert c.breed == 'Persian'
}
assert s == 'Hi !'
println('meow')
}
fn (c Cat) name_detailed(pet_name string) string {
return '$pet_name the ${typeof(c).name}, breed:$c.breed'
}
fn (mut c Cat) set_breed(new string) {
c.breed = new
}
// utility function to override default conversion to string, as a sample
fn (c Cat) str() string {
return 'Custom string conversion for Cat: $c.breed'
}
fn (d Dog) speak(s string) {
assert s == 'Hi !'
println('woof')
}
fn (d Dog) name() string {
assert d.breed == 'Labrador Retriever'
return 'Dog'
}
fn (d Dog) name_detailed(pet_name string) string {
return '$pet_name the ${typeof(d).name}, breed:$d.breed'
}
fn (mut d Dog) set_breed(new string) {
println('Nah')
}
// do not add to Dog the utility function 'str', so the default one will be used, as a sample
struct Bird {
mut:
breed string
}
fn (b Bird) speak(s string) {
println('tweet')
}
fn (b Bird) name() string {
return b.breed
}
fn (b Bird) name_detailed(pet_name string) string {
return '$pet_name the ${typeof(b).name}, breed:$b.breed'
}
fn (mut b Bird) set_breed(new string) {
println('canary')
b.breed = new
}
// do not add to Bird the utility function 'str', so the default one will be used, as a sample
fn is_dog_or_cat(a Animal) bool {
is_dog := a is Dog
is_cat := a is Cat
println('Animal is Dog or Cat: is a Dog: $is_dog, is a Cat: $is_cat')
// return is_dog || is_cat
// shorter syntax
is_dog_or_cat := if (a is Dog) || (a is Cat) { true } else { false }
println('Animal is Dog or Cat: $is_dog_or_cat')
return is_dog_or_cat
}
fn is_dog_or_cat_or_bird(a Animal) bool {
ret := a is Dog || a is Cat || a is Bird
println('Animal is Dog or Cat or Bird: $ret')
return ret
}
fn perform_speak(a Animal) {
println('---- ${@FN}, given Animal: $a ----')
a.speak('Hi !')
assert true
name := a.name()
assert name == 'Dog' || name == 'Cat'
if a is Dog {
assert name == 'Dog'
assert a.breed == 'Labrador Retriever' // test smart casting
println(a.breed)
}
println(a.name())
println('Got animal of type: ${typeof(a).name}') // TODO: get implementation type (if possible)
assert a is Dog || a is Cat
assert is_dog_or_cat(a)
}
fn perform_speak_on_ptr(a &Animal) {
println('---- ${@FN}, given &Animal: $a ----')
a.speak('Hi !')
assert true
name := a.name()
assert name == 'Dog' || name == 'Cat'
if a is Dog {
assert name == 'Dog'
}
println(a.name())
println('Got animal of type: ${typeof(a).name}') // TODO: get implementation type (if possible)
assert a is Dog || a is Cat
assert is_dog_or_cat(a)
}
fn test_perform_speak() {
println('---- ${@FN} ----')
dog := Dog{
breed: 'Labrador Retriever'
}
perform_speak(dog)
perform_speak_on_ptr(dog)
cat := Cat{
breed: 'Persian'
}
perform_speak(cat)
perform_speak(Cat{
breed: 'Persian'
})
perform_speak(new_cat('Persian'))
perform_speak_on_ptr(cat)
perform_speak_on_ptr(Cat{
breed: 'Persian'
})
perform_speak_on_ptr(new_cat('Persian'))
handle_animals([dog, cat])
}
fn change_animal_breed(mut a Animal, new string) {
a.set_breed(new)
}
fn test_interface_ptr_modification() {
println('---- ${@FN} ----')
mut cat := Cat{
breed: 'Persian'
}
change_animal_breed(mut cat, 'Siamese')
assert cat.breed == 'Siamese'
}
fn perform_name_detailed(a Animal) {
name_full := a.name_detailed('MyPet')
println(name_full)
assert name_full.starts_with('MyPet the Dog') || name_full.starts_with('MyPet the Cat')
}
fn test_perform_name_detailed() {
println('---- ${@FN} ----')
dog := Dog{
breed: 'Labrador Retriever'
}
println('Test on Dog: $dog ...') // using default conversion to string
perform_name_detailed(dog)
cat := Cat{}
println('Test on empty Cat: $cat ...')
perform_speak(cat)
println('Test on a Persian Cat: ...')
perform_speak(Cat{
breed: 'Persian'
})
cat_persian2 := Cat{
breed: 'Persian'
}
println('Test on another Persian Cat: "$cat_persian2" ...')
perform_speak(cat_persian2)
cat_persian2_str := cat_persian2.str()
println("Persian Cat 2: '$cat_persian2_str' ...")
assert cat_persian2_str == 'Custom string conversion for Cat: Persian'
println('Test (dummy/empty) on array of animals ...')
handle_animals([dog, cat])
handle_animals_mutable([dog, cat])
assert true
}
fn handle_animals(a []Animal) {
}
fn handle_animals_mutable(a []Animal) {
}
interface Register {
register()
}
struct RegTest {
a int
}
fn (f RegTest) register() {
}
fn handle_reg(r Register) {
r.register()
}
fn test_register() {
println('---- ${@FN} ----')
f := RegTest{}
f.register()
handle_reg(f)
}
interface Speaker2 {
name() string
speak()
return_speaker() Speaker2
mut:
return_speaker2() ?Speaker2
}
struct Boss {
mut:
name string
}
fn (b Boss) name() string {
return b.name
}
fn (b Boss) speak() {
println("i'm $b.name")
}
fn (b &Boss) return_speaker() Speaker2 {
return b
}
fn (mut b Boss) return_speaker2() ?Speaker2 {
if b.name == 'richard' {
return none
}
b.name = 'boss'
return b
}
fn return_speaker2(mut sp Speaker2) Speaker2 {
s := sp.return_speaker()
s2 := sp.return_speaker2() or { return *sp }
s.speak()
s2.speak()
return s2
}
fn test_interface_returning_interface() {
mut b := Boss{'bob'}
assert b.name == 'bob'
s2 := return_speaker2(mut b)
if s2 is Boss {
assert s2.name == 'boss'
}
}
struct Foo {
animal Animal
animals []Animal
}
interface Animal {
name() string
name_detailed(pet_name string) string
speak(s string)
mut:
set_breed(s string)
}
fn test_interface_array() {
println('---- ${@FN} ----')
println('Test on array of animals ...')
mut animals := []Animal{}
animals = [Cat{}, Dog{
breed: 'Labrador Retriever'
}]
assert true
animals << Cat{}
assert true
animals << Bird{}
assert true
// println('Animals array contains: ${animals.str()}') // explicit call to 'str' function
println('Animals array contains: $animals') // implicit call to 'str' function
assert animals.len == 4
}
fn test_interface_ptr_array() {
println('---- ${@FN} ----')
mut animals := []&Animal{}
animals = [Cat{}, Dog{
breed: 'Labrador Retriever'
}]
assert true
animals << Cat{}
assert true
animals << Bird{}
assert true
// println('Animals array contains: ${animals.str()}') // explicit call to 'str' function
println('Animals array contains: $animals') // implicit call to 'str' function
assert animals.len == 4
}
fn test_is() {
println('---- ${@FN} ----')
dog := Dog{}
assert is_dog_int(dog) == 1
}
fn is_dog_int(a Animal) int {
if a is Dog {
return 1
} else {
return 0
}
}
fn test_is_bool() {
println('---- ${@FN} ----')
dog := Dog{}
assert is_dog(dog) == true
assert is_dog_or_cat(dog)
cat := Cat{}
assert is_dog(cat) == false
assert is_dog_or_cat(cat)
bird := Bird{}
assert is_dog(bird) == false
assert !is_dog_or_cat(bird)
assert is_dog_or_cat_or_bird(bird)
}
fn is_dog(a Animal) bool {
println("Got animal: '$a'") // implicit call to 'str' function of implementations
println('with type: ${typeof(a).name}') // get implementation type (if possible)
// sample (additional checks) here
is_dog_or_cat := if (a is Dog) || (a is Cat) { true } else { false }
println('Animal is Dog or Cat: $is_dog_or_cat')
// use/test even another syntax
if a is Dog {
return true
} else {
return false
}
}
fn new_animal() Animal {
dog := Dog{}
return dog
}
fn new_animal2() Animal {
return new_animal()
}
/*
// TODO
fn animal_match(a Animal) {
match a {
Dog { println('(dog)') }
Cat { println('(cat)') }
else { println('(other)' }
}
}
*/
interface II {
mut:
my_field int
}
struct AA {
BB
}
struct BB {
pad [10]byte
mut:
my_field int
}
// the opposite example of interface_mutability_receiver.vv
// related to https://github.com/vlang/v/issues/1081 and https://github.com/vlang/v/issues/7338
// test example code by https://github.com/nedpals copied and adapted from https://github.com/vlang/v/issues/7338
// we accept immutable get_name even if the interface specified `mut` as it is consistent with function param behavior
struct Dog2 {
pub mut:
name string
}
fn (d Dog2) get_name() string {
return d.name
}
// mut get_name might be a bad example
// we try to show that an interface can be more liberal in mut than the implementor,
// while our error check is for the opposite case
interface Animal2 {
mut:
get_name() string
}
fn get_animal_name(mut a Animal2) string {
return a.get_name()
}
fn test_aa() {
println('---- ${@FN} ----')
mut aa := AA{}
mut ii := II(aa)
assert ii.my_field == 0
aa.my_field = 123
assert ii.my_field == 123
ii.my_field = 1234
assert aa.my_field == 1234
mut dog := Dog2{'Doggo'}
println(dog.name)
println(get_animal_name(mut dog))
}
type Text = string
fn (t Text) display() string {
return t
}
interface Displayable {
display() string
}
fn print_displayable(ds ...Displayable) {
for d in ds {
println(d.display())
}
}
fn test_variadic_interface() {
print_displayable(Text('test'), Text('hehe'))
}