diff --git a/develop/ROADMAP.md b/develop/ROADMAP.md index 943bb0b..486dd32 100644 --- a/develop/ROADMAP.md +++ b/develop/ROADMAP.md @@ -12,7 +12,6 @@ - We can return deferred status from modifying operations and spawn/clone methods. - We should have a way to not copy components on deferred spawn/clone. - We can cache default/duplicate per chunk to speed up entity creation with setup hooks. -- We need spawn/clone fuzzy tests! ## Known Issues diff --git a/develop/all.lua b/develop/all.lua index 06b12dd..aaa6343 100644 --- a/develop/all.lua +++ b/develop/all.lua @@ -2,11 +2,13 @@ require 'develop.samples.systems' require 'develop.testing.build_tests' require 'develop.testing.cancel_tests' +require 'develop.testing.clone_tests' require 'develop.testing.locate_tests' require 'develop.testing.main_tests' require 'develop.testing.multi_spawn_tests' require 'develop.testing.name_tests' require 'develop.testing.requires_fragment_tests' +require 'develop.testing.spawn_tests' require 'develop.testing.system_as_query_tests' require 'develop.benchmarks.clone_bmarks' diff --git a/develop/testing/clone_tests.lua b/develop/testing/clone_tests.lua new file mode 100644 index 0000000..7b9edce --- /dev/null +++ b/develop/testing/clone_tests.lua @@ -0,0 +1,397 @@ +local evo = require 'evolved' + +do + do + local p = evo.spawn() + local e = evo.clone(p) + assert(evo.alive(e) and evo.empty(e)) + end + + do + local p = evo.spawn() + local e = evo.clone(p, {}) + assert(evo.alive(e) and evo.empty(e)) + end + + do + local f1, f2 = evo.id(2) + evo.set(f1, evo.REQUIRES, { f2 }) + evo.set(f2, evo.DEFAULT, 42) + + local p = evo.spawn() + local e = evo.clone(p, { [f1] = 'hello' }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2)) + assert(evo.has(e, f1) and evo.get(e, f1) == 'hello') + assert(evo.has(e, f2) and evo.get(e, f2) == 42) + end +end + +do + local f1, f2, f3, f4 = evo.id(4) + evo.set(f1, evo.TAG) + evo.set(f1, evo.REQUIRES, { f2, f3 }) + evo.set(f4, evo.UNIQUE) + + do + local p = evo.spawn { [f4] = 'unique' } + local e = evo.clone(p) + assert(evo.alive(e) and evo.empty(e)) + end + + do + local p = evo.spawn { [f4] = 'unique' } + local e = evo.clone(p, {}) + assert(evo.alive(e) and evo.empty(e)) + end + + do + local p = evo.spawn { [f4] = 'unique' } + local e = evo.clone(p, { [f4] = 'another' }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f4)) + assert(evo.has(e, f4) and evo.get(e, f4) == 'another') + end + + do + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local e = evo.clone(p, { [f4] = 'another' }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f2, f4)) + assert(evo.has(e, f2) and evo.get(e, f2) == 100) + assert(evo.has(e, f4) and evo.get(e, f4) == 'another') + end + + do + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local e = evo.clone(p, { [f1] = 'hello', [f3] = 10 }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3)) + assert(evo.has(e, f1) and evo.get(e, f1) == nil) + assert(evo.has(e, f2) and evo.get(e, f2) == 100) + assert(evo.has(e, f3) and evo.get(e, f3) == 10) + end +end + +do + do + local f1, f2, f3, f4 = evo.id(4) + evo.set(f4, evo.TAG) + + do + local p = evo.spawn { [f2] = 21, [f3] = 'hello', [f4] = true } + local e = evo.clone(p, { [f1] = 'world', [f2] = 10 }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3, f4)) + assert(evo.has(e, f1) and evo.get(e, f1) == 'world') + assert(evo.has(e, f2) and evo.get(e, f2) == 10) + assert(evo.has(e, f3) and evo.get(e, f3) == 'hello') + assert(evo.has(e, f4) and evo.get(e, f4) == nil) + end + end + + do + local f1, f2, f3, f4 = evo.id(4) + evo.set(f2, evo.DEFAULT, 42) + evo.set(f3, evo.DUPLICATE, function() return nil end) + evo.set(f4, evo.TAG) + + do + local p = evo.spawn { [f2] = 21, [f3] = 'hello', [f4] = true } + local e = evo.clone(p, { [f1] = 'world', [f2] = 10 }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3, f4)) + assert(evo.has(e, f1) and evo.get(e, f1) == 'world') + assert(evo.has(e, f2) and evo.get(e, f2) == 10) + assert(evo.has(e, f3) and evo.get(e, f3) == true) + assert(evo.has(e, f4) and evo.get(e, f4) == nil) + end + end +end + +do + local f1, f2, f3, f4 = evo.id(4) + evo.set(f1, evo.TAG) + evo.set(f1, evo.REQUIRES, { f2, f3 }) + evo.set(f2, evo.DEFAULT, 42) + evo.set(f2, evo.DUPLICATE, function(v) return v * 2 end) + evo.set(f3, evo.DUPLICATE, function() return nil end) + evo.set(f4, evo.UNIQUE) + + do + local p = evo.spawn { [f4] = 'unique' } + local e = evo.clone(p) + assert(evo.alive(e) and evo.empty(e)) + end + + do + local p = evo.spawn { [f4] = 'unique' } + local e = evo.clone(p, {}) + assert(evo.alive(e) and evo.empty(e)) + end + + do + local p = evo.spawn { [f4] = 'unique' } + local e = evo.clone(p, { [f4] = 'another' }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f4)) + assert(evo.has(e, f4) and evo.get(e, f4) == 'another') + end + + do + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local e = evo.clone(p, { [f4] = 'another' }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f2, f4)) + assert(evo.has(e, f2) and evo.get(e, f2) == 200 * 2) + assert(evo.has(e, f4) and evo.get(e, f4) == 'another') + end + + do + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local e = evo.clone(p, { [f1] = 'hello', [f2] = 10 }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3)) + assert(evo.has(e, f1) and evo.get(e, f1) == nil) + assert(evo.has(e, f2) and evo.get(e, f2) == 10 * 2) + assert(evo.has(e, f3) and evo.get(e, f3) == true) + end + + local f1_set_count, f1_inserted_count = 0, 0 + local f2_set_sum, f3_inserted_count = 0, 0 + + evo.set(f1, evo.ON_SET, function(e, f, c) + assert(evo.get(e, f) == c) + f1_set_count = f1_set_count + 1 + end) + + evo.set(f1, evo.ON_INSERT, function(e, f, c) + assert(evo.get(e, f) == c) + f1_inserted_count = f1_inserted_count + 1 + end) + + evo.set(f2, evo.ON_SET, function(e, f, c) + assert(evo.get(e, f) == c) + f2_set_sum = f2_set_sum + c + end) + + evo.set(f3, evo.ON_INSERT, function(e, f, c) + assert(evo.get(e, f) == c) + f3_inserted_count = f3_inserted_count + 1 + end) + + do + f1_set_count, f1_inserted_count = 0, 0 + f2_set_sum, f3_inserted_count = 0, 0 + + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local e = evo.clone(p, { [f1] = 'hello', [f2] = 10 }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3)) + assert(evo.has(e, f1) and evo.get(e, f1) == nil) + assert(evo.has(e, f2) and evo.get(e, f2) == 10 * 2) + assert(evo.has(e, f3) and evo.get(e, f3) == true) + + assert(f1_set_count == 1) + assert(f1_inserted_count == 1) + assert(f2_set_sum == 100 * 2 + 10 * 2) + assert(f3_inserted_count == 1) + end +end + +do + local f1, f2, f3, f4 = evo.id(4) + evo.set(f1, evo.TAG) + evo.set(f1, evo.REQUIRES, { f2, f3 }) + evo.set(f4, evo.UNIQUE) + + do + local p = evo.spawn { [f4] = 'unique' } + local es, ec = evo.multi_clone(1, p) + assert(#es == 1 and ec == 1) + for i = 1, ec do + assert(evo.alive(es[i]) and evo.empty(es[i])) + end + end + + do + local p = evo.spawn { [f4] = 'unique' } + local es, ec = evo.multi_clone(2, p, {}) + assert(#es == 2 and ec == 2) + for i = 1, ec do + assert(evo.alive(es[i]) and evo.empty(es[i])) + end + end + + do + local p = evo.spawn { [f4] = 'unique' } + local es, ec = evo.multi_clone(3, p, { [f4] = 'another' }) + assert(#es == 3 and ec == 3) + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f4)) + assert(evo.has(es[i], f4) and evo.get(es[i], f4) == 'another') + end + end + + do + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local es, ec = evo.multi_clone(4, p, { [f4] = 'another' }) + assert(#es == 4 and ec == 4) + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f2, f4)) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 100) + assert(evo.has(es[i], f4) and evo.get(es[i], f4) == 'another') + end + end + + do + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local es, ec = evo.multi_clone(5, p, { [f1] = 'hello', [f3] = 10 }) + assert(#es == 5 and ec == 5) + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 100) + assert(evo.has(es[i], f3) and evo.get(es[i], f3) == 10) + end + end +end + +do + do + local f1, f2, f3, f4 = evo.id(4) + evo.set(f4, evo.TAG) + + do + local p = evo.spawn { [f2] = 21, [f3] = 'hello', [f4] = true } + local es, ec = evo.multi_clone(2, p, { [f1] = 'world', [f2] = 10 }) + assert(#es == 2 and ec == 2) + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3, f4)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 'world') + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 10) + assert(evo.has(es[i], f3) and evo.get(es[i], f3) == 'hello') + assert(evo.has(es[i], f4) and evo.get(es[i], f4) == nil) + end + end + end + + do + local f1, f2, f3, f4 = evo.id(4) + evo.set(f2, evo.DEFAULT, 42) + evo.set(f3, evo.DUPLICATE, function() return nil end) + evo.set(f4, evo.TAG) + + do + local p = evo.spawn { [f2] = 21, [f3] = 'hello', [f4] = true } + local es, ec = evo.multi_clone(2, p, { [f1] = 'world', [f2] = 10 }) + assert(#es == 2 and ec == 2) + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3, f4)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 'world') + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 10) + assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true) + assert(evo.has(es[i], f4) and evo.get(es[i], f4) == nil) + end + end + end +end + +do + local f1, f2, f3, f4 = evo.id(4) + evo.set(f1, evo.TAG) + evo.set(f1, evo.REQUIRES, { f2, f3 }) + evo.set(f2, evo.DEFAULT, 42) + evo.set(f2, evo.DUPLICATE, function(v) return v * 2 end) + evo.set(f3, evo.DUPLICATE, function() return nil end) + evo.set(f4, evo.UNIQUE) + + do + local p = evo.spawn { [f4] = 'unique' } + local es, ec = evo.multi_clone(3, p) + assert(#es == 3 and ec == 3) + + for i = 1, ec do + assert(evo.alive(es[i]) and evo.empty(es[i])) + end + end + + do + local p = evo.spawn { [f4] = 'unique' } + local es, ec = evo.multi_clone(3, p, {}) + assert(#es == 3 and ec == 3) + + for i = 1, ec do + assert(evo.alive(es[i]) and evo.empty(es[i])) + end + end + + do + local p = evo.spawn { [f4] = 'unique' } + local es, ec = evo.multi_clone(2, p, { [f4] = 'another' }) + assert(#es == 2 and ec == 2) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f4)) + assert(evo.has(es[i], f4) and evo.get(es[i], f4) == 'another') + end + end + + do + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local es, ec = evo.multi_clone(4, p, { [f4] = 'another' }) + assert(#es == 4 and ec == 4) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f2, f4)) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 200 * 2) + assert(evo.has(es[i], f4) and evo.get(es[i], f4) == 'another') + end + end + + do + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local es, ec = evo.multi_clone(5, p, { [f1] = 'hello', [f2] = 10 }) + assert(#es == 5 and ec == 5) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 10 * 2) + assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true) + end + end + + local f1_set_count, f1_inserted_count = 0, 0 + local f2_set_sum, f3_inserted_count = 0, 0 + + evo.set(f1, evo.ON_SET, function(e, f, c) + assert(evo.get(e, f) == c) + f1_set_count = f1_set_count + 1 + end) + + evo.set(f1, evo.ON_INSERT, function(e, f, c) + assert(evo.get(e, f) == c) + f1_inserted_count = f1_inserted_count + 1 + end) + + evo.set(f2, evo.ON_SET, function(e, f, c) + assert(evo.get(e, f) == c) + f2_set_sum = f2_set_sum + c + end) + + evo.set(f3, evo.ON_INSERT, function(e, f, c) + assert(evo.get(e, f) == c) + f3_inserted_count = f3_inserted_count + 1 + end) + + do + f1_set_count, f1_inserted_count = 0, 0 + f2_set_sum, f3_inserted_count = 0, 0 + + local p = evo.spawn { [f2] = 100, [f4] = 'unique' } + local es, ec = evo.multi_clone(1, p, { [f1] = 'hello', [f2] = 10 }) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == nil) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 10 * 2) + assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true) + + assert(f1_set_count == 1) + assert(f1_inserted_count == 1) + assert(f2_set_sum == 100 * 2 + 10 * 2) + assert(f3_inserted_count == 1) + end + end +end diff --git a/develop/testing/spawn_tests.lua b/develop/testing/spawn_tests.lua new file mode 100644 index 0000000..1927817 --- /dev/null +++ b/develop/testing/spawn_tests.lua @@ -0,0 +1,329 @@ +local evo = require 'evolved' + +do + do + local e = evo.spawn() + assert(evo.alive(e) and evo.empty(e)) + end + + do + local e = evo.spawn({}) + assert(evo.alive(e) and evo.empty(e)) + end +end + +do + local f1, f2, f3 = evo.id(3) + evo.set(f2, evo.REQUIRES, { f1, f3 }) + + do + local e = evo.spawn({ [f1] = 42 }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1)) + assert(evo.has(e, f1) and evo.get(e, f1) == 42) + end + + do + local e = evo.spawn({ [f1] = 42, [f2] = 'hello' }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3)) + assert(evo.has(e, f1) and evo.get(e, f1) == 42) + assert(evo.has(e, f2) and evo.get(e, f2) == 'hello') + assert(evo.has(e, f3) and evo.get(e, f3) == true) + end +end + +do + local f1, f2, f3 = evo.id(3) + evo.set(f2, evo.REQUIRES, { f1, f3 }) + evo.set(f3, evo.DEFAULT, 21) + evo.set(f3, evo.REQUIRES, { f2 }) + + do + local e = evo.spawn({ [f1] = 42 }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1)) + assert(evo.has(e, f1) and evo.get(e, f1) == 42) + end + + do + local e = evo.spawn({ [f1] = 42, [f2] = 'hello' }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3)) + assert(evo.has(e, f1) and evo.get(e, f1) == 42) + assert(evo.has(e, f2) and evo.get(e, f2) == 'hello') + assert(evo.has(e, f3) and evo.get(e, f3) == 21) + end +end + +do + local f1, f2, f3, f4 = evo.id(4) + evo.set(f2, evo.DUPLICATE, function() return nil end) + evo.set(f2, evo.REQUIRES, { f1, f3, f4 }) + evo.set(f3, evo.DEFAULT, 21) + evo.set(f3, evo.DUPLICATE, function(v) return v * 3 end) + evo.set(f3, evo.REQUIRES, { f2 }) + + do + local e = evo.spawn({ [f1] = 42 }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1)) + assert(evo.has(e, f1) and evo.get(e, f1) == 42) + end + + do + local e = evo.spawn({ [f1] = 42, [f2] = true }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3, f4)) + assert(evo.has(e, f1) and evo.get(e, f1) == 42) + assert(evo.has(e, f2) and evo.get(e, f2) == true) + assert(evo.has(e, f3) and evo.get(e, f3) == 21 * 3) + assert(evo.has(e, f4) and evo.get(e, f4) == true) + end +end + +do + local f1, f2, f3 = evo.id(3) + evo.set(f2, evo.REQUIRES, { f3 }) + evo.set(f3, evo.TAG) + + local f2_set_sum, f2_inserted_sum = 0, 0 + local f3_set_count, f3_inserted_count = 0, 0 + + evo.set(f2, evo.ON_SET, function(e, f, c) + assert(c == 42) + assert(evo.get(e, f) == c) + assert(f == f2) + f2_set_sum = f2_set_sum + c + end) + + evo.set(f2, evo.ON_INSERT, function(e, f, c) + assert(c == 42) + assert(evo.get(e, f) == c) + assert(f == f2) + f2_inserted_sum = f2_inserted_sum + c + end) + + evo.set(f3, evo.ON_SET, function(e, f, c) + assert(c == nil) + assert(evo.get(e, f) == c) + assert(f == f3) + f3_set_count = f3_set_count + 1 + end) + + evo.set(f3, evo.ON_INSERT, function(e, f, c) + assert(c == nil) + assert(evo.get(e, f) == c) + assert(f == f3) + f3_inserted_count = f3_inserted_count + 1 + end) + + do + f3_set_count, f3_inserted_count = 0, 0 + local e = evo.spawn({ [f1] = 'hello', [f2] = 42 }) + assert(evo.alive(e) and not evo.empty(e) and evo.locate(e) == evo.chunk(f1, f2, f3)) + assert(f2_set_sum == 42 and f2_inserted_sum == 42) + assert(f3_set_count == 1 and f3_inserted_count == 1) + end +end + +do + do + local es, ec = evo.multi_spawn(2) + assert(#es == 2 and ec == 2) + + for i = 1, ec do + assert(evo.alive(es[i]) and evo.empty(es[i])) + end + end + + do + local es, ec = evo.multi_spawn(2, {}) + assert(#es == 2 and ec == 2) + + for i = 1, ec do + assert(evo.alive(es[i]) and evo.empty(es[i])) + end + end +end + +do + local f1, f2 = evo.id(2) + + do + local es, ec = evo.multi_spawn(3, { [f1] = 42 }) + assert(#es == 3 and ec == 3) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) + end + end + + do + local es, ec = evo.multi_spawn(3, { [f1] = 42, [f2] = 'hello' }) + assert(#es == 3 and ec == 3) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'hello') + end + end +end + +do + local f1, f2 = evo.id(2) + evo.set(f1, evo.REQUIRES, { f2 }) + + do + local es, ec = evo.multi_spawn(3, { [f1] = 42 }) + assert(#es == 3 and ec == 3) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == true) + end + end +end + +do + local f1, f2 = evo.id(2) + evo.set(f1, evo.REQUIRES, { f2 }) + + do + local es, ec = evo.multi_spawn(1, { [f1] = 42 }) + assert(#es == 1 and ec == 1) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == true) + end + end +end + +do + local f1, f2, f3 = evo.id(3) + evo.set(f1, evo.REQUIRES, { f2, f3 }) + evo.set(f2, evo.DEFAULT, 'hello') + + do + local es, ec = evo.multi_spawn(4, { [f1] = 42 }) + assert(#es == 4 and ec == 4) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'hello') + assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true) + end + end + + do + local es, ec = evo.multi_spawn(4, { [f1] = 42, [f2] = 'world' }) + assert(#es == 4 and ec == 4) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'world') + assert(evo.has(es[i], f3) and evo.get(es[i], f3) == true) + end + end + + do + local es, ec = evo.multi_spawn(4, { [f1] = 42, [f2] = 'world', [f3] = false }) + assert(#es == 4 and ec == 4) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == 42) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'world') + assert(evo.has(es[i], f3) and evo.get(es[i], f3) == false) + end + end +end + +do + local f1, f2 = evo.id(2) + evo.set(f1, evo.REQUIRES, { f2 }) + evo.set(f1, evo.DUPLICATE, function() return nil end) + evo.set(f2, evo.DEFAULT, 'hello') + evo.set(f2, evo.DUPLICATE, function(v) return v .. '!' end) + + do + local es, ec = evo.multi_spawn(4, { [f1] = 42 }) + assert(#es == 4 and ec == 4) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == true) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'hello!') + end + end + + do + local es, ec = evo.multi_spawn(4, { [f1] = 42, [f2] = 'world' }) + assert(#es == 4 and ec == 4) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2)) + assert(evo.has(es[i], f1) and evo.get(es[i], f1) == true) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'world!') + end + end + + do + local es, ec = evo.multi_spawn(4, { [f2] = 'hello world' }) + assert(#es == 4 and ec == 4) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f2)) + assert(evo.has(es[i], f2) and evo.get(es[i], f2) == 'hello world!') + end + end +end + +do + local f1, f2, f3 = evo.id(3) + evo.set(f2, evo.REQUIRES, { f3 }) + evo.set(f3, evo.TAG) + + local f2_set_sum, f2_inserted_sum = 0, 0 + local f3_set_count, f3_inserted_count = 0, 0 + + evo.set(f2, evo.ON_SET, function(e, f, c) + assert(c == 42) + assert(evo.get(e, f) == c) + assert(f == f2) + f2_set_sum = f2_set_sum + c + end) + + evo.set(f2, evo.ON_INSERT, function(e, f, c) + assert(c == 42) + assert(evo.get(e, f) == c) + assert(f == f2) + f2_inserted_sum = f2_inserted_sum + c + end) + + evo.set(f3, evo.ON_SET, function(e, f, c) + assert(c == nil) + assert(evo.get(e, f) == c) + assert(f == f3) + f3_set_count = f3_set_count + 1 + end) + + evo.set(f3, evo.ON_INSERT, function(e, f, c) + assert(c == nil) + assert(evo.get(e, f) == c) + assert(f == f3) + f3_inserted_count = f3_inserted_count + 1 + end) + + do + local es, ec = evo.multi_spawn(3, { [f1] = 'hello', [f2] = 42 }) + assert(#es == 3 and ec == 3) + + for i = 1, ec do + assert(evo.alive(es[i]) and not evo.empty(es[i]) and evo.locate(es[i]) == evo.chunk(f1, f2, f3)) + assert(f2_set_sum == 42 * 3 and f2_inserted_sum == 42 * 3) + assert(f3_set_count == 3 and f3_inserted_count == 3) + end + end +end