//
// Copyright 2024 Formata, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#[base]
type Base {
fn isBase(): bool {
return true;
}
}
type Extends extends Base {
fn isBase(): bool {
return false;
}
}
return: {
obj empty: {}
fn create_base(): Base {
return self.empty;
}
#[test]
fn cast_on_return() {
let base = self.create_base();
assertEq(typename base, 'Base');
assert(base.isBase());
}
}
as: {
obj as_cast: {}
#[test]
fn cast_on_as() {
let as_cast = self.as_cast as Base;
assertEq(typename as_cast, 'Base');
assert(as_cast.instanceOf('Base'));
assert(as_cast.isBase());
}
}
poly: {
Extends extends_obj: {}
fn get_base(object: obj): Base {
return object;
}
#[test]
fn instance_of_catch() {
assertEq(typename self.extends_obj, 'Extends');
let object = self.get_base(self.extends_obj);
assertEq(typename object, 'Extends');
assert(object.instanceOf('Extends'));
assert(object.instanceOf('Base'));
assertNot(object.isBase());
assert(object.Base::isBase());
}
}
upcast: {
obj empty: {}
#[test]
fn upcast_extends() {
let object = self.empty as Extends;
assertNot(object.isBase());
assertEq(typename object, 'Extends');
assert(object.instanceOf('Extends'));
assert(object.instanceOf('Base'));
object = object as Base; // Already of type Base...
assertNot(object.isBase());
assertEq(typename object, 'Extends');
assert(object.instanceOf('Extends'));
assert(object.instanceOf('Base'));
assert(object.upcast());
assert(object.isBase());
assertEq(typename object, 'Base');
assert(object.instanceOf('Base'));
assertNot(object.instanceOf('Extends'));
assertNot(object.upcast()); // Nowhere to upcast to...
assert(object.instanceOf('Base'));
assert(object.prototype() != null);
let base_attributes = object.prototypeAttributes();
assertEq(base_attributes, map([('base', null)]));
assert(object.removePrototype());
assertNot(object.instanceOf('Base'));
}
}
errors: {
type NoDefaults {
x: int;
y: int;
}
#[test]
#[errors]
fn no_defaults() {
let inst = new NoDefaults {}; // does not have an x or y defined, so error
}
#[test]
fn has_defaults() {
let inst = new {
x: 4;
y: 5;
};
inst = inst as NoDefaults;
assertEq(inst.x, 4);
assertEq(inst.y, 5);
}
#[test]
#[errors]
fn wrong_types() {
let inst = new NoDefaults {
x: 'hi'
y: 5
}; // Errors because of wrong types!
}
}
default_values: {
type Defaults {
x: float = 20cm;
y: float = 2m;
z: float = 10mm;
}
type ExtendsDefaults extends Defaults {
q: int = 2;
}
#[test]
fn create_defaults() {
let inst = new Defaults {};
assertEq(inst.x, 20cm);
assertEq(inst.y, 2m);
assertEq(inst.z, 10mm);
}
#[test]
fn cast_defaults() {
let inst = new {};
inst = inst as Defaults;
assertEq(inst.x, 20cm);
assertEq(inst.y, 2m);
assertEq(inst.z, 10mm);
}
#[test]
fn extends_cast_defaults() {
let inst = new {};
inst = inst as ExtendsDefaults;
assertEq(inst.x, 20cm);
assertEq(inst.y, 2m);
assertEq(inst.z, 10mm);
assertEq(inst.q, 2);
}
#[test]
fn downcast_defaults() {
let inst = new Defaults {};
inst = inst as ExtendsDefaults;
assertEq(inst.x, 20cm);
assertEq(inst.y, 2m);
assertEq(inst.z, 10mm);
assertEq(inst.q, 2);
}
empty: {}
#[test]
fn field_cast() {
let inst = self.empty as ExtendsDefaults;
assertEq(self.empty.x, 20cm);
assertEq(self.empty.y, 2m);
assertEq(self.empty.z, 10mm);
assertEq(self.empty.q, 2);
}
}