tml-validation

TML basic validation test suite

npm install tml-validation
8 downloads in the last month

tml-validation(3) -- basic validation tests

SYNOPSIS

tml-validation basic validation tests.

OPTIONS

SYNTAX

ENVIRONMENT

RETURN VALUES

STANDARDS

SECURITY CONSIDERATIONS

BUGS

HISTORY

AUTHOR

SEE ALSO

IMPLEMENTATION


Validation

    @purpose Sample test of APL;
    @author Erin Phillips;
    @version 1.0;
    @history 2013-04-30 EMP [0.0.1-1] add-tml-build;
    @history 2013-05-01 EMP [0.0.1-2] fix-fire-dynamic-event;

resources

    TMLR = tml-runtime [TmlRuntime]

locals

    uuid = TMLR::uuid

tags

    TAG_2QSTR = "Hello";
    TAG_1QSTR = 'Hello';
    TAG_3QSTR = """
        |Hello there
        |are you there?""";
    TAG_NUM = 99;
    TAG_OBJ = {a:1};
    TAG_LIST = [1,2,3];
    TAG_FBOOL = false;
    TAG_TBOOL = true;
    TAG_PARAMSTR = (con 'Hello ' :1);
    TAG_PARAMNUMS = (add 100 :1 :2 :3);
    TAG_PARAMHASH = {a: :1, b: :2};

notes

    @usecase COMMENTS
        Use case narrative;

    @slice COMMENTS.1
        Use case slice narrative;

    @skin COLORS
        Notes on aesthetics;

    @layout BANNER
        Notes on layout;

    @flow WORK.1
        Notes on program flow;

    @feature COMMENT-TAGS
        Notes on program capabilities which meet stated needs;

    @need STRUCTURED-COMMENTS
        Notes on needs a module must address;

    @ref WORK.1 BANNER COLORS COMMENTS.1
        Notes on references to other notes;

messages

    ERR-EVCNT Expected {2} events, but received {1};

    ERR-IO.100 {*} This is an IO error;
    WRN-IO.100 This is an IO warning;
    DBG-IO.100 This is an IO debug notice;
    INF-IO.100 This is an IO informational notice;
    APP-IO.100 This is an IO application message;

    ERR-IO.101 {*} {1} {2}, this is an IO error {3};
    WRN-IO.101 This is an IO warning {1};
    DBG-IO.101 This is an IO debug notice {1};
    INF-IO.101 This is an IO informational notice {1};
    APP-IO.101 This is an IO application message {1};

code

    @purpose The following are examples of the different types of comments available in APL;
    @param a Some descriptive detail about 'a';
    @author Arthur Name;
    @design A subtle design or implementation concept relevant to the code;
    @purpose A design or implementation decision;
    @result The expected outcome;
    @see A reference to something else relevant to the code;
    @usage Guidance for using a construct;
    @version Version;
    @deadcode
        Code which is instructive, but no longer effective.
        Semi-colons must be removed;

-- PATTERNS --;

pattern patStateCheck :name

    <<<
    ###method is:Name -> !=ami :NAME;
    >>>

pattern patGlobalVar :name :varType :initialValue

    @param name name of the global variable;
    @param varType data type;
    @param initialValue the initial value;

    <<<
    ##var global:Name = :initialValue
    ##sensor get:Name -> :varType = global:Name;
    >>>

pattern patPrefixedGlobalVar :name :varType :initialValue

    <<<
    ##var :name+Global = :initialValue
    ##sensor :name+Get -> :varType = :name+Global;
    >>>

pattern patCapsGlobalVar :name :varType :initialValue

    <<<
    ##var global:NAME = :initialValue
    ##sensor get:NAME -> :varType = global:NAME;
    >>>

pattern patType :n :v

    <<<
    ##type :n(:v);
    ###method getSeventySeven -> #=77;
    >>>

pattern patTypeMeth :n :v :meth

    @param name name of the type;
    @param v type parameter;
    @param meth a method defininition;

    <<<
    ##type :n(:v);
    ###method getSeventySeven -> #=77;
      :meth
    >>>

pattern patTest :n :a :b

    <<<
    ##test-eq : :n
        :a vs :b
    >>>

pattern patCaseIf :val :lbl :typ

    <<<

test-ok : should detect case type :typ

    case-if :val
        # :lbl='number'
        $ :lbl='string'
        * :lbl='list'
        %TypeA :lbl='TypeA'
        :AspectA :lbl='AspectA'
        :ServiceA :lbl='ServiceA'
        % :lbl='hash'
    ;
    enforce eq$ :lbl ':typ' 'Case failed'
    ;        
    >>>

-- STATICS --;

sensor readAddition :Addition -> #=a.getAddValue();

    @purpose take a type who uses Addition, and return its value;

sensor readNumeric %Numeric -> #=a.getValue();

    @purpose take a type Numeric, and return its value;

sensor readNumberService :NumberService -> #=a.getValue();

    @purpose take a type who provides NumberService, and return
    its value;

sensor readNumber %Number -> #=a.getValue();

    @purpose take a Number type, and return the value;

render patGlobalVar a $ 'hello ';

render patGlobalVar b $ 'world';

render patPrefixedGlobalVar a $ '_hello ';

render patPrefixedGlobalVar b $ '_world';

render patCapsGlobalVar aValue # 99;

anvil opPositive v?rulePositive -> #=v;

rule rulePositive :val

    (ge :val 0)

rule ruleLessThan :val :upper

    (lt :val :upper)

sensor f1a ?;

sensor f1b opt ?;

sensor f2 $;

sensor f3 #;

sensor f4 *;

sensor f5 *2;

sensor f6 *2+;

sensor f7 *-2;

sensor f8 *1-5;

sensor f9 &;

sensor f10 &2;

sensor f11 &2+;

sensor f12 &-2;

sensor f13 &1-5;

sensor f14 %;

sensor f15 %TypeD;

sensor f16 :ServiceD;

sensor f17 ?rulePositive;

sensor f18 ?ruleLessThan(5);

var mainCount=0

    @purpose counter for main Bus events;

sensor getMainCount -> # = mainCount;

    @design the function getMainCount is necessary to expose
    the module-local mainCount variable to the external
    test module;

bus MainBus

    @purpose central testing bus;

event MainBus.addValue # &

    add= mainCount a; b();

event once MainBus.addValueOnce # &

    add= mainCount a; b();

sender addMain # &

    fire MainBus.addValue(a,b);

sender addMainOnce # &

    fire MainBus.addValueOnce(a,b);

bus SecondBus

    @purpose secondary testing bus;

var secondCount=0

    @purpose counter for second Bus events;

sensor getSecondCount -> # = secondCount;

sender incSecondCount

    add= secondCount a;;

sender addSecond # &

    fire SecondBus('addValue')(a,b);

rule rulePositive :v

    (ge :v 0)

var totalSomething = 0

anvil addCallback # &1

    b(add= totalSomething a);

sensor getTotalSomething ->#=totalSomething;

-- TYPES --;


type Numeric(@value#)

static maxInteger = 4294967295

    @purpose Maximum valid integer value;

method getValue ->#=@value;


aspect Addition

    @usage Aspect provides a method for adding to a value;

method addToValue #->:Addition = @me

    add= @value a;;

method getAddValue ->#=@value;


aspect Subtraction

    @usage Aspect provides a method for subtracting from a value;

method subtractFromValue #->:Subtraction = @me

    sub= @value a;;

method getSubValue ->#=@value;


service NumberService

method getValue -> #;

method addToValue # -> :Addition;

method subtractFromValue # -> :Subtraction;


type Number(value#)

    extends Numeric(value)
    uses Addition
    uses Subtraction
    provides NumberService;

operator << # -> :NumberService = @me

    @purpose adds a value;
    @addToValue(a);

operator << -> :NumberService = @me

    @purpose adds a list of values;
    each a as value @addToValue(value);;

type NumberRange(value#,@min#,@max#)

    @usage stateful tracking of value relative to a min and max value.
        <min triggers UNDERFLOW.
        >max triggers OVERFLOW;
    extends Number(0)
    initial state STABLE -> UNDERFLOW OVERFLOW;
    state STABLE -> UNDERFLOW OVERFLOW;
    state UNDERFLOW -> STABLE;
    state OVERFLOW -> STABLE;
    (@me << value);

render patStateCheck stable;

render patStateCheck underflow;

render patStateCheck overflow;

method reset # -> this

    @purpose resets @value and state;
    @value=a iam STABLE;

operator << # -> this

    @purpose adds a value, detecting UNDERFLOW or OVERFLOW.
        Throws if attempted after UNDERFLOW or OVERFLOW;
    @design overloads parent operator;
    vars newval=add @value a;;
    enforce ami STABLE 'Cannot modify unstable value.'
    if lt newval @min
        iam UNDERFLOW
    else
        if gt newval @max
            iam OVERFLOW
        else
            @design '3' semis: (1) if (1) if (1) op;
            @Number.<<(a);;;

operator << -> this

    @design overloads parent operator;
    each a as value (@me << value);;

singleton type NumberSingleton(value#)

    extends Number(value)
    @usage single-instance number;

render patType MyTypeA <<<>>>;

render patTypeMeth MyTypeB

    <<<@str$,@num#>>>
    <<<
    ###method getStr ->$=@str;
    ###method getNum ->#=@num;
    >>>;

aspect AspectA

method getNine -> #=9;

service ServiceA

method getA -> #;

type TypeA

type TypeB

    uses AspectA

type TypeC

    provides ServiceA

method getA -> #=99;

service ServiceD;

method getIt -> #;

type TypeD provides ServiceD

method getIt ->#=9;

type TypeE;

method setIt ?ruleLessThan(5) -> this;

type MyType;

-- TESTS --;


test ASSIGN

    vars o1
         o2={a:1,b:2}
         o3=[1,2,3]
         o3a o3b o3c o3d o3e
         o4a=99
         o4b={a:1,b:2}
         ;
    o1=99
    delete o2.a
    (o3a,o3b,o3c)=o3
    (o3d,o3e)=o3
    unset o4a
    unset o4b.a

test-eq : should assign a value

    o1 vs 99

test-eq : should delete a hash key

    exists o2 'a' vs false

test-eq : should assign using var list

    o3a vs 1

test-eq : should assign using var list

    o3b vs 2

test-eq : should assign using var list

    o3c vs 3

test-eq : should assign using mismatched var list

    o3d vs 1

test-eq : should assign using mismatched var list

    o3e vs 2

test-eq : should unset a var

    noval o4a vs true

test-eq : should unset a hash value

    noval o4b.a vs true

    ;

test FLOW

    vars o1=0
         o2=0
         o3x
         o3a=0
         o3b='a'
         o3c=[]
         o3d={}
         o3e=new TypeA()
         o3f=new TypeB()
         o3g=new TypeC()
         o4a='a' o4b='a'
         o5a='a' o5b='a'
         o6a='zz' o6b='a'
         o7a='a' o7b='a'
         ;

    while lt o1 10
        add= o1 1;
    finally
        add= o1 100;
    ;

test-eq : should iterate using while

    o1 vs 110

    while lt o2 10
        add= o2 1;
        if ge o2 5
            break;
    ;

test-eq : should break

    o2 vs 5

render patCaseIf o3a o3x number;

render patCaseIf o3b o3x string;

render patCaseIf o3c o3x list;

render patCaseIf o3d o3x hash;

render patCaseIf o3e o3x TypeA;

render patCaseIf o3f o3x AspectA;

render patCaseIf o3g o3x ServiceA;

    if eq$ o4a 'a'
        con= o4b 'b';;

    if ne$ o4a 'a'
        con= o4b 'b';;

test-eq : should test if

    o4b vs 'ab'

    if eq$ o5a 'z'
        con= o5b 'z';
    else-if eq$ o5a 'a'
        con= o5b 'B';
    else
        con= o5b 'x';
    ;

test-eq : should follow if-else

    o5b vs 'aB'

    if eq$ o6a 'z'
        con= o6b 'z';
    else-if eq$ o6a 'a'
        con= o6b 'B';
    else
        con= o6b 'x';
    ;

test-eq : should find final else

    o6b vs 'ax'

    ifnot eq$ o7a 'zz'
        con= o7b 'z';
    ;

test-eq : should test ifnot

    o7b vs 'az'

test-throw : 'should throw'

    throw 'oops!'
    ;

    ;

test STRING

    vars o1a='abc' o1b='++abc'
         o2a='abc' o2b='abc++'
         o3a='hello' o3b='hello'
         o4a='hello' o4b='hello'
            ;

    ensure-leading o1a '++'
    ensure-leading o1b '++'

    ensure-trailing o2a '++'
    ensure-trailing o2b '++'

    excise= o3b 2 2

          replace= o4a /[el]/g func $ -> $ b=as-string char-code a;

test-eq : should concatenate a semi-colon

    (con 'string' ';') vs 'string;'

test-eq : should ensure leading string

    o1a vs '++abc'

test-eq : should not duplicate leading string

    o1b vs '++abc'

test-eq : should ensure trailing string

    o2a vs 'abc++'

test-eq : should not duplicate trailing string

    o2b vs 'abc++'

test-eq : should excise portion of string

    excise o3a 1 3 vs 'ho'

test-eq : should excise portion of string

    o3b vs 'heo'

test-eq : should convert numeric to string

    as-string 5 vs '5'

test-eq : should concatenate numerics as strings

    (con as-string 5 as-string 99) vs '599'

test-eq : should replace using func

    o4a vs 'h101108108o'

    ;

test WHEN

    vars v1="a" v2="b" v3="c" t1 t2 t3 t4;
    when v1
        "a" "b" then t1=v1;;
    when v2
        "a" "b" then t2=v2;;
    when v3
        "a" "b" then t3=v1;
        "c" then t3=v3;;
    when v3
        "a" "b" then t3=v1;
        else t4=v3;

test-eq : should find first match

    t1 vs v1

test-eq : should find second match

    t2 vs v2

test-eq : should use second condition

    t3 vs v3

test-eq : should perform else when no match

    t4 vs v3
    ;

test ITERATOR

    vars l1=['a',1,'b',2,'c',3,4,5]
         v1={stringCount:0
            ,numberCount:0
            ,totalCount:0
            ,order:''}
         l2=[0,1,2,3,4,5,6,7,'a','b','c','d','e','f','g','h','i','j',
            0,1,2,3,4,5,6,7,'a','b','c','d','e','f','g','h','i','j',
            0,1,2,3,4,5,6,7,'a','b','c','d','e','f','g','h','i','j']
         v2={stringCount:0
            ,numberCount:0
            ,totalCount:0
            ,order:''}
         v3={order:''}
         v4={order:''}
         counter=func ? % &
                    case-if a
                        $ add= b.stringCount 1;
                        # add= b.numberCount 1;
                    ;
                    con= b.order a;
                    c()
                 ;
          summer=func %
                    a.totalCount
                        = add a.stringCount a.numberCount;
                 ;
         v5a='abcde嗰g' v5b='' v5c=''
         v6='' v7=''
         v8='' v9='' v10='' v11=''
         l12=[1,2,3,4,5] v12a='' v12b=''
         h13={a:1,b:2,c:3} v13=0
    ;

test-async : should process list of items async but in order

    series-each l1 as v
        setTimeout(
            func counter(v,v1,next);
            ,rand 10 150
        )
    finally
        summer(v1)
        enforce eq v1.stringCount 3 'String count failed'
        enforce eq v1.numberCount 5 'Number count failed'
        enforce eq v1.totalCount 8 'Total count failed'
        enforce eq$ v1.order 'a1b2c345' 'Series not in order'
        done();;

test-async : should process list of items in parallel

    parallel-each l2 as v batch 9
        setTimeout(
            func counter(v,v2,next);
            ,rand 10 150
        )
    finally
        summer(v2)
        replace= v2.order /[0-7]{8}[a-z]{10}/g ''
        enforce eq v2.stringCount 30 'String count failed'
        enforce eq v2.numberCount 24 'Number count failed'
        enforce eq v2.totalCount 54 'Total count failed'
        enforce ne$ v2.order '' 'Series in order'
        done();;

test-async : should process functions asynchronously

    async
        func setTimeout(
                func con= v3.order 'a'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v3.order 'b'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v3.order 'c'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v3.order 'd'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v3.order 'e'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v3.order 'f'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v3.order 'g'; next();
                ,rand 10 150);
    finally
        con= v3.order '*';
        enforce ne$ v2.order 'abcdefg*' 'Series in order'
        done();;

test-async : should process functions asynchronously but in series

    async series
        func setTimeout(
                func con= v4.order 'a'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v4.order 'b'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v4.order 'c'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v4.order 'd'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v4.order 'e'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v4.order 'f'; next();
                ,rand 10 150);
        func setTimeout(
                func con= v4.order 'g'; next();
                ,rand 10 150);
    finally
        con= v4.order '*';
        enforce eq$ v4.order 'abcdefg*' 'Series not in order'
        done();;

    each-char v5a as ch
        con= v5b ch;;

    reverse each-char v5a as ch
        con= v5c ch;;

test-eq : should iterate chars in order

    v5b vs v5a

test-eq : should iterate chars in reverse order

    v5c vs 'g嗰edcba'

    each-index 5 as i
        con= v6 i;;

test-eq : should iterate 0 to N-1 in order

    v6 vs '01234'

    reverse each-index 5 as i
        con= v7 i;;

test-eq : should iterate 0 to N-1 in reverse order

    v7 vs '43210'

    count 1 to 5 as i
        con= v8 i;;

test-eq : should count A to B in order

    v8 vs '12345'

    reverse count 1 to 5 as i
        con= v9 i;;

test-eq : should count A to B in reverse order

    v9 vs '54321'

    count 1 to 5 step 2 as i
        con= v10 i;;

test-eq : should count A to B step C in order

    v10 vs '135'

    reverse count 1 to 6 step 2 as i
        con= v11 i;;

test-eq : should count A to B step C in reverse order

    v11 vs '642'

    each l12 as v con= v12a v;;

test-eq : should iterate list items in order

    v12a vs '12345'

    reverse each l12 as v con= v12b v;;

test-eq : should iterate list items in reverse order

    v12b vs '54321'

    each-key h13 as k add= v13 h13.(k);;

test-eq : should iterate hash keys

    v13 vs 6

    ;

test LIST

    vars l1=[1,2,3] l2=[1,2,3];

    unshift l1 4 5 6;
    push l2 4 5 6;

test-eq : should prepend items to a list

    l1[0] vs 4

test-eq : should prepend items to a list

    l1[1] vs 5

test-eq : should prepend items to a list

    l1[2] vs 6

test-eq : should append items to a list

    l2[3] vs 4

test-eq : should append items to a list

    l2[4] vs 5

test-eq : should append items to a list

    l2[5] vs 6

    ;

test TAG

    vars obja=##TAG_OBJ;
       objb=##TAG_OBJ;
       lista=##TAG_LIST;
       listb=##TAG_LIST;
       pstr=##TAG_PARAMSTR 'World';
       pnum=##TAG_PARAMNUMS 1 2 3;
       v1a=null
       v1b=null
       v0=3
       v1=4
       ;

    objb.a=50
    pop listb

    ##TAG_INLINE1 = <<<'Test Message'>>>
    ##TAG_INLINE2 = <<<(con 'Test ' :1)>>>
    ##TAG_INLINEADD1IF3 = <<<
        if eq :1 3
            add= :1 1;;
    >>>
    ##TAG_INLINEADD1IFELSE = <<<
        if eq :1 3
            add= :1 1;
        else
            :2
        ;
    >>>

    ##TAG_INLINEADD1IF3 v0;

    ##TAG_INLINEADD1IFELSE v1 <<< 
    ##TAG_INLINEADD1IFELSE :1 <<<
        add= :1 2;
    >>>;
    >>>;

test-eq : should paste if statement

  v0 vs 4

test-eq : should paste nested if statement

  v1 vs 6

test-eq : should support single-quote value

  ##TAG_1QSTR; vs "Hello"

test-eq : should support double-quote value

  ##TAG_2QSTR; vs "Hello"

test-eq : should support triple-quote value

  ##TAG_3QSTR; vs "Hello there\nare you there?"

test-eq : should support number value

  ##TAG_NUM; vs 99

test-eq : should support object value

  isa obja % vs true

test-eq : should copy object values

  obja.a vs 1

test-eq : should be not be object reference

  ne objb.a obja.a vs true

test-eq : should support list value

  isa lista * vs true

test-eq : should copy list values

  lista[1] vs 2

test-ne : should be not be list reference

  item-count lista vs item-count listb 

test-eq : should set parameterized string tag

  pstr vs 'Hello World'

test-eq : should set parameterized numeric tag

  pnum vs 106

    v1a=##TAG_INLINE1;
    v1b=##TAG_INLINE2 'Tag';

test-eq : should set inline expression tag

    v1a vs 'Test Message'

test-eq : should set inline expression tag

    v1b vs 'Test Tag'

    ;

test BUS

test EVENT

    @purpose send a bunch of one-time events, only the first should actually fire;

    addMainOnce(1,func;)
    addMainOnce(1,func;)
    addMainOnce(1,func;)
    addMainOnce(1,func;)

test-async : should fire normal and single-use events

    async 
      func addMain(1,next);
      func addMain(1,next);
      func addMain(1,next);
    finally
      enforce eq getMainCount() 4 ERR-EVCNT(getMainCount(),4)
      done()
    ;;;

test SUBSCRIBE

test-async : should subscribe normally and to single-use events

    @design two subscriptions to the same event, with
      the second subscription a one-time subscription;

    subscribe SecondBus.addValue
      func # & incSecondCount(a) b();

    subscribe once SecondBus.addValue
      func # & incSecondCount(a);
      @design because of the dual subscription, I need to
          skip the callback to keep from exiting the
          async list early;

    async
      func addSecond(1,next);
      func addSecond(1,next);
      func addSecond(1,next);
    finally
      enforce eq getSecondCount() 4 ERR-EVCNT(getSecondCount(),4)
      done()
    ;;;;

test MESSAGE

test-eq : should render error message;

    ERR-IO.100() vs 'ERR-IO.100 This is an IO error'

test-eq : should render warning message;

    WRN-IO.100() vs 'This is an IO warning'

test-eq : should render warning message;

    DBG-IO.100() vs 'This is an IO debug notice'

test-eq : should render warning message;

    INF-IO.100() vs 'This is an IO informational notice'

test-eq : should render warning message;

    APP-IO.100() vs 'This is an IO application message'

test-eq : should render error message with param;

    ERR-IO.101('Hello','There',99) vs 'ERR-IO.101 Hello There, this is an IO error 99'


    ;

test OP_CALLS

test-throw : op taking any-type should reject empty arg list

f1a();

test-ok : op taking opt-any-type should accept no args

f1b();

test-ok : op taking any-type should accept numeric arg

f1a(9);

test-ok : op taking any-type should accept hash arg

f1a({});

test-ok : op taking any-type should accept list arg

f1a([]);

test-ok : op taking string should accept string arg

f2('a');

test-throw : op taking string should reject numeric

f2(1);

test-ok : op taking numeric should accept numeric

f3(99);

test-throw : op taking numeric should reject list

f3([]);

test-ok : op taking list should accept list

f4([]);

test-throw : op taking list should reject numeric

f4(2);

test-ok : op taking definite list should accept matching list

f5([1,2]);

test-throw : op taking definite list should reject shorter list

f5([2]);

test-throw : op taking definite list should reject longer list

f5([2,2,2]);

test-ok : op taking min-length list should accept longer list

f6([1,2,4,5,6]);

test-ok : op taking min-length list should accept min-length list

f6([1,2]);

test-throw : op taking min-length list should reject shorter list

f6([2]);

test-ok : op taking max-length list should accept max-length list

f7([1,2]);

test-ok : op taking max-length list should accept shorter list

f7([1]);

test-throw : op taking max-length list should reject longer list

f7([2,3,4]);

test-ok : op taking bounded list should accept max-length list

f8([1,2,3,4,5]);

test-ok : op taking bounded list should accept min-length list

f8([1]);

test-throw : op taking bounded list should reject shorter list

f8([]);

test-throw : op taking bounded list should reject longer list

f8([1,2,3,4,5,6]);

test-ok : op taking no-arg func should accept same

f9(func;);

test-throw : op taking no-arg func should reject func taking args

f9(9);

test-ok : op taking definite-arg func should accept same

f10(func # #;);

test-throw : op taking definite-arg func should reject func too few args

f10(func #;);

test-throw : op taking definite-arg func should reject func too many args

f10(func # # #;);

test-ok : op taking min-args func should accept func min-length args

f11(func # #;);

test-ok : op taking min-args func should accept func with more args

f11(func # # #;);

test-throw : op taking min-args func should reject func too few args

f11(func #;);

test-throw : op taking min-args func should reject func with no args

f11(func;);

test-ok : op taking max-args func should accept func with max-length args

f12(func # #;);

test-ok : op taking max-args func should accept func with fewer args

f12(func #;);

test-ok : op taking max-args func should accept func with no args

f12(func;);

test-throw : op taking max-args func should reject func with too many args

f12(func % % %;);

test-ok : op taking bounded-args should accept func with min args

f13(func #;);

test-ok : op taking bounded-args should accept func with max args

f13(func $ $ $ $ #;);

test-throw : op taking bounded-args should reject func with too few args

f13(func;);

test-throw : op taking bounded-args should reject func with too many args

f13(func % % % % $ %;);

test-ok : op taking object should accept same

f14({});

test-throw : op taking object should reject numeric

f14(2);

test-ok : op taking type should accept same

f15(new TypeD());

test-throw : op taking type should reject numeric

f15(3);

test-ok : op taking service should accept type providing that service

f16(new TypeD());

test-throw : op taking service should reject numeric

f16(99);

test-throw : op taking service should reject type not providing that service

f16(new TypeE());

test-ok : op taking rule should accept value which complies

f17(3);

test-throw : op taking service should reject value which fails

f17(-1);

test-ok : op taking parameterized rule should accept value which complies

f18(3);

test-throw : op taking parameterized rule should reject value which fails

f18(99);

test-ok : method taking rule should accept value which complies

(new TypeE()).setIt(4);

test-throw : method taking parameterized rule should reject value which fails

(new TypeE()).setIt(99);

;

test RULE

vars v1=1 v2=-1 v3=99;

test-eq : should apply rule yielding true

(v1?rulePositive) vs true

test-eq : should apply rule yielding false

(v2?rulePositive) vs false

test-eq : should apply parameterized rule yielding true

(v3?ruleLessThan(100)) vs true

test-eq : should apply parameterized rule yielding false

(v3?ruleLessThan(50)) vs false

test-eq : should call method using rule on param

opPositive(v1) vs v1

test-throw : should throw on method call with rule violation

opPositive(v2);

;

test PATTERN

test-eq : should create global var

(con getA() getB()) vs 'hello world'

test-eq : should create prefixed global var

(con aGet() bGet()) vs '_hello _world'

test-eq : should create all-caps global var

getAVALUE() vs 99

test-eq : should create type

(new MyTypeA()).getSeventySeven() vs 77

test-eq : should create type

(new MyTypeB('hello',99)).getSeventySeven() vs 77

test-eq : should call string method on type

(new MyTypeB('hello',99)).getStr() vs 'hello'

test-eq : should call numeric method on type

(new MyTypeB('hello',99)).getNum() vs 99

render patTest 'should create test from pattern'

(add 3 2 3 4) 12;

;

test ASPECT

test-eq : should call aspect method

    (new Number(99)).addToValue(1).getValue() vs 100

test-eq : should ensure arg uses aspect

    readAddition(new Number(11)) vs 11
    ;

test TYPE

test-eq : should accept matching type arg

    readNumeric(new Numeric(11)) vs 11

test-throw : should throw when aspect passed instead of type

    readNumeric(new Addition());

test-eq : should accept sub-type arg

    readNumeric(new Number(11)) vs 11

test-eq : should apply operator

    (new Number(11) << 22).getValue() vs 33

test-eq : should apply list operator

    (new Number(11) <*< [10,11,12]).getValue() vs 44

test-eq : should initialize state

    (new NumberRange(11,10,12)).isStable() vs true

test-eq : should return state

    (new NumberRange(11,10,12)).isOverflow() vs false

test-eq : should change state to overflow

    (new NumberRange(15,10,12)).isOverflow() vs true

test-eq : should change state to underflow

    (new NumberRange(8,10,12)).isUnderflow() vs true

test-throw : should throw on state violation

    ((new NumberRange(8,10,12)) << 100);

test-eq : should only make one singleton instance

    (new NumberSingleton(55)).getValue()
        vs (new NumberSingleton(99)).getValue()
    ;
npm loves you