import {NavigationState, NavigationError, navigation_objectify, navigation_deobjectify} from "../js/navigation_state.mjs"
import {NavigationStateProtected} from "../js/navigation_state_protected.mjs"
import {assert_equal} from "/assert.mjs"

function objectify_and_deobjectify(state, correct_objectified) {
	let objectified = navigation_objectify(state)
	if (objectified.type == 'NavigationError') delete objectified['stack']
	assert_equal(0, 2, objectified, correct_objectified)
	const deobjectified = navigation_deobjectify(objectified)
	const objectified_again = navigation_objectify(deobjectified)
	if (objectified_again.type == 'NavigationError') delete objectified_again['stack']
	assert_equal(0, 2, objectified, objectified_again)
}


function random_state() {
	let ret = {};
	for (let i = 0; i < 10; i++) {

	}
}


export async function runTests() {
	console.group("NavigationState")

	console.group("Construct and get value")
	const state = NavigationState.create({ a: "b", c: "d" })
	assert_equal(0, 1, state.get("a"), "b")
	assert_equal(0, 1, state.get(["a"]), "b")
	assert_equal(0, 1, state.get(["a", "b"]), undefined)
	assert_equal(0, 1, state.get("b"), undefined)
	assert_equal(0, 1, state.get(["b"]), undefined)
	const state_with_private = NavigationState.create({ a: "b", c: "d" }).private_merge({ "e": "f", "g": { "h": "i" } })
	assert_equal(0, 1, state_with_private.private_get("e"), "f")
	assert_equal(0, 1, state_with_private.private_get(["e"]), "f")
	assert_equal(0, 1, state_with_private.private_get(["e", "f"]), undefined)
	assert_equal(0, 1, state_with_private.private_get("g"), { "h": "i" })
	assert_equal(0, 1, state_with_private.private_get(["g","h"]), "i")
	const error = new NavigationError("Custom", "msg")
	console.groupEnd()


	console.group("Basic objectify and deobjectify")
	objectify_and_deobjectify(state, { "type": "NavigationState", "state":  {"shared":{"a":"b","c":"d"},"private":{}} })
	objectify_and_deobjectify(state_with_private, { "type": "NavigationState", "state":  {"shared":{"a":"b","c":"d"},"private":{"e":"f","g":{"h":"i"}}} })
	objectify_and_deobjectify(error, { "type": "NavigationError", "kind":"Custom", "message":"msg" })
	console.groupEnd()

	console.group("Merge object")
	console.group("shared")
	const merge_shared_base = NavigationState.create({ a: "b" })
	objectify_and_deobjectify(merge_shared_base.merge({ "c": "d" }), { "type": "NavigationState", "state": { "shared": { "a": "b", "c": "d" }, "private": {} } })
	// checking if previous command didn't alter the base
	objectify_and_deobjectify(merge_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base.merge([], { "c": "d" }), { "type": "NavigationState", "state": { "shared": { "a": "b", "c": "d" }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base.merge([], { "a": "c" }), { "type": "NavigationState", "state": { "shared": { "a": "c" }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base.merge(["scope"], { "c": "d" }), { "type": "NavigationState", "state": { "shared": { "a": "b", "scope": { "shared": { "c": "d" }, "private": {} } }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base.merge(["scope1", "scope2"], {"e": "d"}), { "type": "NavigationState", "state": { "shared": { "a": "b", "scope1": { "shared": { "scope2": { "shared": { "e": "d" }, "private": {} } }, "private": {} } }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base.merge({ "e": "d", "scope1": { "x": "y" } }).merge({ "scope1": { "a": "b" } }).merge(["scope1"], { "n": "k" }), { "type": "NavigationState", "state": { "shared": { "a": "b", "e": "d", "scope1": { "shared": { "x": "y", "a": "b", "n": "k" }, "private": {} } }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base.merge({ "a": null }), { "type": "NavigationState", "state": { "shared": { }, "private": {} } })
	objectify_and_deobjectify(merge_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	console.groupEnd()
	console.group("private")
	const private_merge_base = NavigationState.create().private_merge({ a: "b" })
	objectify_and_deobjectify(private_merge_base.private_merge({ "c": "d" }), { "type": "NavigationState", "state": { "shared": { }, "private": {"a": "b", "c": "d"} } })
	// checking if previous command didn't alter the base
	objectify_and_deobjectify(private_merge_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	objectify_and_deobjectify(private_merge_base.private_merge([], { "c": "d" }), { "type": "NavigationState", "state": { "shared": { }, "private": {"a": "b", "c": "d"} } })
	objectify_and_deobjectify(private_merge_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	objectify_and_deobjectify(private_merge_base.private_merge([], { "a": "c" }), { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "c" } } })
	objectify_and_deobjectify(private_merge_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	objectify_and_deobjectify(private_merge_base.private_merge(["scope"], { "c": "d" }), { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b", "scope": { "c": "d" }} } })
	objectify_and_deobjectify(private_merge_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	objectify_and_deobjectify(private_merge_base.private_merge(["scope1", "scope2"], {"e": "d"}), { "type": "NavigationState", "state": { "shared": {}, "private": { "a": "b", "scope1": { "scope2": { "e": "d" } } } } })
	objectify_and_deobjectify(private_merge_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	objectify_and_deobjectify(private_merge_base.private_merge({ "e": "d", "scope1": { "x": "y" } }).private_merge({ "scope1": { "a": "b"} }).private_merge(["scope1"], {"n": "k"}), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","e":"d","scope1":{"x":"y","a":"b","n":"k"}}}})
	objectify_and_deobjectify(private_merge_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	objectify_and_deobjectify(private_merge_base.private_merge({ "a": null }), { "type": "NavigationState", "state": { "shared": { }, "private": {} } })
	objectify_and_deobjectify(private_merge_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	console.groupEnd()
	console.groupEnd()


	console.group("Set value")
	console.group("shared")
	const set_shared_base = NavigationState.create({ a: "b" })
	objectify_and_deobjectify(set_shared_base.set("c", "d"), { "type": "NavigationState", "state": { "shared": { "a": "b", "c": "d" }, "private": {} } })
	// checking if previous command didn't alter the base
	objectify_and_deobjectify(set_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	objectify_and_deobjectify(set_shared_base.set(["scope", "c"], "d"), { "type": "NavigationState", "state": { "shared": { "a": "b", "scope": { "shared": { "c": "d" }, "private": {} } }, "private": {} } })
	objectify_and_deobjectify(set_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	objectify_and_deobjectify(set_shared_base.set(["scope1", "scope2", "e"], "d"), { "type": "NavigationState", "state": { "shared": { "a": "b", "scope1": { "shared": { "scope2": { "shared": { "e": "d" }, "private": {} } }, "private": {} } }, "private": {} } })
	objectify_and_deobjectify(set_shared_base, { "type": "NavigationState", "state": { "shared": { "a": "b" }, "private": {} } })
	console.groupEnd()
	console.group("private")
	const private_set_base = NavigationState.create().private_merge({a: "b"})
	objectify_and_deobjectify(private_set_base.private_set("c", "d"), { "type": "NavigationState", "state": { "shared": { }, "private": {"a": "b", "c": "d"} } })
	// checking if previous command didn't alter the base
	objectify_and_deobjectify(private_set_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	objectify_and_deobjectify(private_set_base.private_set(["scope", "c"], "d"), { "type": "NavigationState", "state": { "shared": {}, "private": { "a": "b", "scope": { "c": "d" } } } })
	objectify_and_deobjectify(private_set_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	objectify_and_deobjectify(private_set_base.private_set(["scope1", "scope2", "e"], "d"), { "type": "NavigationState", "state": { "shared": {}, "private": { "a": "b", "scope1": { "scope2": { "e": "d" } } } } })
	objectify_and_deobjectify(private_set_base, { "type": "NavigationState", "state": { "shared": { }, "private": { "a": "b" } } })
	console.groupEnd()
	console.groupEnd()


	console.group("Remove value")
	console.group("shared")
	const remove_shared_base = NavigationState.create({ "a": "b", "scope1": { "scope2": { c: "d" } }, "scope3": { "x": "y" } })
	assert_equal(0, 1, remove_shared_base.get(["scope1", "scope2", "c"]), "d")
	assert_equal(0, 1, remove_shared_base.get(["scope1", "scope2", "d"]), undefined)
	objectify_and_deobjectify(remove_shared_base.remove("a"), {"type":"NavigationState","state":{"shared":{"scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(remove_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(remove_shared_base.remove("scope3"), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(remove_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(remove_shared_base.remove(["scope3", "x"]), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{},"private":{}}},"private":{}}})
	objectify_and_deobjectify(remove_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(remove_shared_base.remove("non-existent"), {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(remove_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(remove_shared_base.remove(["non-existent", "x"]), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x": "y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(remove_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	console.groupEnd()
	console.group("private")
	const private_remove_base = NavigationState.create().private_merge({ "a": "b", "scope1": { "scope2": { c: "d" } }, "scope3": { "x": "y" } })
	assert_equal(0, 1, private_remove_base.private_get(["scope1", "scope2", "c"]), "d")
	assert_equal(0, 1, private_remove_base.private_get(["scope1", "scope2", "d"]), undefined)
	objectify_and_deobjectify(private_remove_base.private_remove("a"), {"type":"NavigationState","state":{"shared":{},"private":{"scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(private_remove_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(private_remove_base.private_remove("scope3"), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}}}}})
	objectify_and_deobjectify(private_remove_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(private_remove_base.private_remove(["scope3", "x"]), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}},"scope3":{}}}})
	objectify_and_deobjectify(private_remove_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(private_remove_base.private_remove("non-existent"), {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(private_remove_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(private_remove_base.private_remove(["non-existent", "x"]), {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(private_remove_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	console.groupEnd()
	console.groupEnd()

	//TODO recursive and non?
	console.group("Strip private")
	const strip_private_base = NavigationState.create({ a: "b", scope1: { scope2: { c: "d" } }, scope3: { x: "y" } }).private_merge({ p1: "p2" }).scope(["scope1", "scope2"]).private_merge({ p_c: "p_d" }).root_scope().scope(["scope3"]).private_merge({ p_x: "p_y" }).root_scope()
	objectify_and_deobjectify(strip_private_base, { "type": "NavigationState", "state": { "shared": { "a": "b", "scope1": { "shared": { "scope2": { "shared": { "c": "d" }, "private": { "p_c": "p_d" } } }, "private": {} }, "scope3": { "shared": { "x": "y" }, "private": { "p_x": "p_y" } } }, "private": { "p1": "p2" } } })
	objectify_and_deobjectify(strip_private_base.strip_private_recursively(), { "type": "NavigationState", "state": { "shared": { "a": "b", "scope1": { "shared": { "scope2": { "shared": { "c": "d" }, "private": {} } }, "private": {} }, "scope3": { "shared": { "x": "y" }, "private": {} } }, "private": {} } })
	console.groupEnd()

	console.group("Trim empty branches")
	const trim_base = NavigationState.create({ "a": "b", "empty": {}, "scope1": { "scope2": { "c": "d", "empty": {} } }, "scope3": { "x": "y", "empty": { "nested": {} } } }).private_merge({ "p1": "p2", "empty": {} })
	objectify_and_deobjectify(trim_base, {"type":"NavigationState","state":{"shared":{"a":"b","empty":{"shared":{},"private":{}},"scope1":{"shared":{"scope2":{"shared":{"c":"d","empty":{"shared":{},"private":{}}},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y","empty":{"shared":{"nested":{"shared":{},"private":{}}},"private":{}}},"private":{}}},"private":{"p1":"p2","empty":{}}}})
	objectify_and_deobjectify(trim_base[NavigationStateProtected.trim_empty_branches](), { "type": "NavigationState", "state": { "shared": { "a": "b", "scope1": { "shared": { "scope2": { "shared": { "c": "d" }, "private": {} } }, "private": {} }, "scope3": { "shared": { "x": "y" }, "private": {} } }, "private": {"p1": "p2"} } })
	objectify_and_deobjectify(trim_base, {"type":"NavigationState","state":{"shared":{"a":"b","empty":{"shared":{},"private":{}},"scope1":{"shared":{"scope2":{"shared":{"c":"d","empty":{"shared":{},"private":{}}},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y","empty":{"shared":{"nested":{"shared":{},"private":{}}},"private":{}}},"private":{}}},"private":{"p1":"p2","empty":{}}}})
	objectify_and_deobjectify(trim_base[NavigationStateProtected.trim_empty_branches](), { "type": "NavigationState", "state": { "shared": { "a": "b", "scope1": { "shared": { "scope2": { "shared": { "c": "d" }, "private": {} } }, "private": {} }, "scope3": { "shared": { "x": "y" }, "private": {} } }, "private": {"p1": "p2"} } })
	const trim_all_empty = NavigationState.create({ "empty1": {}, "empty2": { "nested": {} }, "nonempty": "value" })
	objectify_and_deobjectify(trim_all_empty[NavigationStateProtected.trim_empty_branches](), { "type": "NavigationState", "state": { "shared": { "nonempty": "value" }, "private": {} }})
	console.groupEnd()


	console.group("Remove values outside of a set")
	console.group("shared")
	const filter_values_shared_base = NavigationState.create({ "a": "b", "scope1": { "scope2": { c: "d" } }, "scope3": { "x": "y" } })
	objectify_and_deobjectify(filter_values_shared_base.keep_only_values("x", []), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_values_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_values_shared_base.keep_only_values("a", []), {"type":"NavigationState","state":{"shared":{"scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_values_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_values_shared_base.keep_only_values("a", ["x", "b"]), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_values_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_values_shared_base.keep_only_values(["scope1", "scope2"], ["c"]), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_values_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_values_shared_base.keep_only_values(["scope1", "scope2","c"], ["d"]), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_values_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	console.groupEnd()
	console.group("private")
	const filter_values_private_base = NavigationState.create().private_merge({ "a": "b", "scope1": { "scope2": { c: "d" } }, "scope3": { "x": "y" } })
	objectify_and_deobjectify(filter_values_private_base.private_keep_only_values("x", []), {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_values_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_values_private_base.private_keep_only_values("a", []), {"type":"NavigationState","state":{"shared":{},"private":{"scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_values_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_values_private_base.private_keep_only_values("a", ["x", "b"]), {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_values_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_values_private_base.private_keep_only_values(["scope1", "scope2"], ["c"]), {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_values_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_values_private_base.private_keep_only_values(["scope1", "scope2","c"], ["d"]), {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_values_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a": "b", "scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	console.groupEnd()
	console.groupEnd()

	console.group("Remove keys outside of a set")
	console.group("shared")
	const filter_keys_shared_base = NavigationState.create({ "a": "b", "scope1": { "scope2": { c: "d" } }, "scope3": { "x": "y" } })
	objectify_and_deobjectify(filter_keys_shared_base.keep_only_keys("x", []), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_keys_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_keys_shared_base.keep_only_keys(["scope1", "scope3"]), {"type":"NavigationState","state":{"shared":{"scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_keys_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_keys_shared_base.keep_only_keys("x"), {"type":"NavigationState","state":{"shared":{},"private":{}}})
	objectify_and_deobjectify(filter_keys_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_keys_shared_base.keep_only_keys(["scope1", "scope2"], ["c"]), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_keys_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_keys_shared_base.keep_only_keys(["scope1", "scope2"], ["d"]), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	objectify_and_deobjectify(filter_keys_shared_base, {"type":"NavigationState","state":{"shared":{"a": "b", "scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}},"scope3":{"shared":{"x":"y"},"private":{}}},"private":{}}})
	console.groupEnd()
	console.group("private")
	const filter_keys_private_base = NavigationState.create().private_merge({ "a": "b", "scope1": { "scope2": { c: "d" } }, "scope3": { "x": "y" } })
	objectify_and_deobjectify(filter_keys_private_base.private_keep_only_keys("x", []), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_keys_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_keys_private_base.private_keep_only_keys(["scope1", "scope3"]), {"type":"NavigationState","state":{"shared":{},"private":{"scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_keys_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_keys_private_base.private_keep_only_keys("x"), {"type":"NavigationState","state":{"shared":{},"private":{}}})
	objectify_and_deobjectify(filter_keys_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_keys_private_base.private_keep_only_keys(["scope1", "scope2"], ["c"]), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_keys_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_keys_private_base.private_keep_only_keys(["scope1", "scope2"], ["d"]), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{}},"scope3":{"x":"y"}}}})
	objectify_and_deobjectify(filter_keys_private_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}},"scope3":{"x":"y"}}}})
	console.groupEnd()
	console.groupEnd()

	console.group("Default to")
	console.group("shared")
	const default_to_base = NavigationState.create({ "a": "b", "scope1": { "scope2": { c: "d" } } })
	objectify_and_deobjectify(default_to_base.default_to("a", "c"), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(default_to_base, {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(default_to_base.default_to("nonexistent", "c"), {"type":"NavigationState","state":{"shared":{"a":"b","nonexistent": "c","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(default_to_base, {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(default_to_base.default_to(["scope1", "scope2", "c"], "e"), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(default_to_base, {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(default_to_base.default_to(["scope1", "scope2", "nonexistent"], "e"), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d", "nonexistent":"e"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(default_to_base, {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(default_to_base.default_to(["scope1", "new"], { "x": "y" }), {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}},"new":{"shared":{"x":"y"},"private":{}}},"private":{}}},"private":{}}})
	objectify_and_deobjectify(default_to_base, {"type":"NavigationState","state":{"shared":{"a":"b","scope1":{"shared":{"scope2":{"shared":{"c":"d"},"private":{}}},"private":{}}},"private":{}}})
	console.groupEnd()
	console.group("private")
	const private_default_to_base = NavigationState.create().private_merge({ "a": "b", "scope1": { "scope2": { c: "d" } } })
	objectify_and_deobjectify(private_default_to_base.private_default_to("a", "c"), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}}}}})
	objectify_and_deobjectify(private_default_to_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}}}}})
	objectify_and_deobjectify(private_default_to_base.private_default_to("nonexistent", "c"), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}},"nonexistent":"c"}}})
	objectify_and_deobjectify(private_default_to_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}}}}})
	objectify_and_deobjectify(private_default_to_base.private_default_to(["scope1", "scope2", "c"], "e"), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}}}}})
	objectify_and_deobjectify(private_default_to_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}}}}})
	objectify_and_deobjectify(private_default_to_base.private_default_to(["scope1", "scope2", "nonexistent"], "e"), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d","nonexistent":"e"}}}}})
	objectify_and_deobjectify(private_default_to_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}}}}})
	objectify_and_deobjectify(private_default_to_base.private_default_to(["scope1", "new"], { "x": "y" }), {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"},"new":{"x":"y"}}}}})
	objectify_and_deobjectify(private_default_to_base, {"type":"NavigationState","state":{"shared":{},"private":{"a":"b","scope1":{"scope2":{"c":"d"}}}}})
	console.groupEnd()
	console.groupEnd()


	//hrefs and navigate functions are tested by StateManager's tests

	document.getElementById("state_result").innerHTML = "OK"
}
