const Hash = s2.Hash.new;
scope {
var h = Hash();
assert h inherits s2.Hash;
var tableSize = h.hashSize();
assert 'integer' === typename tableSize;
assert tableSize > 0;
unset tableSize;
assert 0 === h.entryCount();
h.insert(1,-1.0);
assert 1 === h.entryCount();
assert -1.0 === h.search(1);
h.insert(0,1.0);
var c = 0;
h.eachEntry(function(k,v){
assert 'integer' === typename k;
assert 'double' === typename v;
c = c + 1;
});
assert h.entryCount() === c;
assert h.containsEntry(1);
assert !h.containsEntry(2);
var keys = h.entryKeys(), vals = h.entryValues();
assert 'array' === typename keys;
assert 'array' === typename vals;
assert vals.length() == c;
assert keys.length() == c;
unset keys, vals;
h.remove(-1);
assert 2 === h.entryCount();
h.insert(1, 0.0);
assert 2 === h.entryCount();
h.remove(1);
assert 1 === h.entryCount();
h.clearEntries();
assert 0 === h.entryCount();
}
scope {
var h1 = s2.Hash.new(11), h2 = s2.Hash.new(23);
h1.insert(1, 2);
h1.insert(2, 3);
h1.eachEntry(h2, h2.insert);
assert 2 === h2.entryCount();
h1.clearEntries();
assert !h1.entryCount();
h2.eachEntry(h1);
assert 2 === h1.entryCount();
var o = {};
h1.eachEntry(o, o.set);
assert 3 === o.2;
assert 2 === o.1;
h2.clearEntries();
h1.eachEntry(h2);
assert 2 === h2.entryCount();
assert 3 === h2.search(2);
assert 2 === h2.search(1);
h1.insert('f', proc f(){
assert f === this;
return this;
});
assert h1#'f' === (h1#'f')();
assert h1#'f' === h1#'f'();
}
scope {
var h = s2.Hash.new(11);
assert !h.hasEntries();
assert 11 === h.hashSize();
h.insert(1, 2);
assert h.hasEntries();
h.insert(3, 4);
assert 2 === h.entryCount();
h.resize(3);
assert 3 === h.hashSize();
assert 4 === h # 3;
assert 2 === h # 1;
assert 2 === h.entryCount();
assert h.hasEntries();
assert 'CWAL_RC_RANGE' === catch{h.resize(-1)}.codeString();
assert 'CWAL_RC_MISUSE' === catch{h.resize()}.codeString();
}
if(s2.getResultCodeHash){
const rch = s2.getResultCodeHash();
assert rch.entryCount() > 90 /* === 102 as of this writing */;
assert rch === s2.getResultCodeHash() /* result is cached */;
assert 'integer' === typename rch # 'CWAL_RC_OOM';
assert 'string' === typename rch # 0 /* the only code with a well-defined value! */;
}
scope { /* takeProperties() */
var src, h;
const reset = proc(){
src = {a:1, b:-1, c:0};
h = s2.Hash.new(5);
};
reset();
h.insert('a', 'aaaa');
h.takeProperties(src,1);
assert 1 === h # 'a';
assert undefined === src.a;
assert undefined === src.b;
assert undefined === src.c;
assert(src.isEmpty());
reset();
h.insert('a', 'aaaa');
h.takeProperties(src,-1);
assert 'aaaa' === h # 'a';
assert 1 === src.a;
assert undefined === src.b;
assert undefined === src.c;
assert(!src.isEmpty());
reset();
h.insert('a', 'aaaa');
const ex = catch h.takeProperties(src,0);
assert ex;
assert 'CWAL_RC_ALREADY_EXISTS' === ex.codeString();
assert 1 === src.a;
/* src.b and src.c might have been moved already:
internal order is undefined and mutable
at runtime. */
assert !src.isEmpty();
}
assert 999 === scope {
/*
testing fix:
https://fossil.wanderinghorse.net/r/cwal/info/5041ab1deee33194
If it's broken, this will crash if built in debug mode,
triggering a cwal-level assertion, possibly a different one
depending on the type of the scope result value's type.
*/
{#a: 999}#'a'
};
scope {
/** 2020-02-06: dot-length operator (lhs.#) now, on hashes,
resolves to the number of hash entries. */
assert 3 === {# a:1, b:1, c:1}.#;
}
scope {
/* 2020-02-18: {#x:=y} assigns x as a const hash entry */
const h = {# a:1, b:=2};
assert 1 === h#'a';
assert 2 === h#'b';
assert 3 === h.insert('a',3);
assert 'CWAL_RC_CONST_VIOLATION' === catch h.insert('b',1).codeString();
assert 2 === h.#;
assert 2 === foreach(#h=>k,v) 'b'===k && break v;
}
scope {
/** 2020-02-20: inline expansion of object properties into an
object literal, similar to JS's {...otherObj}. This is
currently explicitly disallowed for hash literals because of
potential semantic ambiguities in handling of hash vs. object
properties.
*/
const ex = catch{ {#@{a:1}} };
assert 'CWAL_RC_TYPE' === ex.codeString();
assert ex.message.indexOf('hash literal') > 0;
}