flok 0.0.41 → 0.0.42
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/kern/pagers/pg_dummy.js +18 -0
- data/app/kern/services/vm.rb +361 -34
- data/docs/services/vm.md +69 -40
- data/docs/services/vm/diff.md +156 -0
- data/docs/services/vm/pagers.md +3 -2
- data/lib/flok/user_compiler.rb +3 -0
- data/lib/flok/version.rb +1 -1
- data/spec/env/kern.rb +19 -0
- data/spec/etc/user_compiler/controller0bg.rb +13 -0
- data/spec/etc/user_compiler_spec.rb +19 -12
- data/spec/kern/assets/global_on_entry5.rb +28 -0
- data/spec/kern/assets/vm/controller0_diff.rb +47 -0
- data/spec/kern/assets/vm/pg_dummy/config.rb +10 -0
- data/spec/kern/assets/vm/pg_mem/write.rb +1 -1
- data/spec/kern/assets/vm/pg_mem/write2.rb +1 -1
- data/spec/kern/assets/vm/vm_commit_pages.js +108 -0
- data/spec/kern/assets/vm/vm_diff_pages.js +140 -0
- data/spec/kern/assets/vm/vm_transaction_diff_pages.js +150 -0
- data/spec/kern/controller_spec.rb +19 -0
- data/spec/kern/vm_service_functional_spec.rb +1111 -0
- data/spec/kern/vm_service_spec.rb +84 -185
- data/spec/kern/vm_transaction_spec.rb +375 -0
- metadata +22 -4
- data/spec/kern/vm_service_spec2.rb +0 -39
@@ -0,0 +1,140 @@
|
|
1
|
+
//Page Factor
|
2
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
3
|
+
function PageFactory(head, next) {
|
4
|
+
this.head = head;
|
5
|
+
this.next = next;
|
6
|
+
this.entries = [];
|
7
|
+
}
|
8
|
+
|
9
|
+
//Add an entry
|
10
|
+
PageFactory.prototype.addEntry = function(eid, value) {
|
11
|
+
this.entries.push({_id: eid, _sig: value, value: value});
|
12
|
+
}
|
13
|
+
|
14
|
+
//This adds up to four entrys that can be represented as a square:
|
15
|
+
//-------------
|
16
|
+
//| id0 | id1 |
|
17
|
+
//-------------
|
18
|
+
//| id2 | id3 |
|
19
|
+
//-------------
|
20
|
+
//Leaving out parts of the values array will not add those entries, e.g. ["Square", null, null, "Triangle"]
|
21
|
+
//--------------------|
|
22
|
+
//| Square | null |
|
23
|
+
//--------------------|
|
24
|
+
//| null | Triangle |
|
25
|
+
//--------------------|
|
26
|
+
//Where 'Square' is id0 and 'Triangle' is id3
|
27
|
+
PageFactory.prototype.addEntryFourSquare = function(values) {
|
28
|
+
if (values.length != 4) {
|
29
|
+
throw "FourSquare requires for values. Make values null if you don't need them"
|
30
|
+
}
|
31
|
+
|
32
|
+
for (var i = 0; i < values.length; ++i) {
|
33
|
+
if (values[i]) {
|
34
|
+
this.addEntry("id"+i, values[i]);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
//Same as addEntryFourSquare but takes an index parameter before the
|
40
|
+
//value that sets the id of each element
|
41
|
+
//e.g. addEntryFourSquareCustomIds([["id0, "A"], ["id2, "B"], ["id1, "C"], ["id3, "D"]]).
|
42
|
+
//[
|
43
|
+
// {_id: "id0", value: "A", _sig: "A"},
|
44
|
+
// {_id: "id3", value: "D", _sig: "D"},
|
45
|
+
// {_id: "id2", value: "C", _sig: "C"},
|
46
|
+
// {_id: "id1", value: "B", _sig: "B"},
|
47
|
+
//]
|
48
|
+
PageFactory.prototype.addEntryFourSquareCustomIds = function(values) {
|
49
|
+
for (var i = 0; i < values.length; ++i) {
|
50
|
+
//Get pair
|
51
|
+
var pair = values[i];
|
52
|
+
if (pair.length != 2) {
|
53
|
+
throw "FourSquareShuffle accepts pairs. E.g. ['id0', 'A']"
|
54
|
+
}
|
55
|
+
|
56
|
+
var id = pair[0];
|
57
|
+
var value = pair[1];
|
58
|
+
|
59
|
+
this.addEntry(id, value);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
//Returns a page
|
64
|
+
PageFactory.prototype.compile = function() {
|
65
|
+
var page = vm_create_page("default");
|
66
|
+
page._head = this.head;
|
67
|
+
page._next = this.next;
|
68
|
+
|
69
|
+
page.entries = this.entries;
|
70
|
+
|
71
|
+
vm_rehash_page(page);
|
72
|
+
vm_reindex_page(page);
|
73
|
+
|
74
|
+
return page;
|
75
|
+
}
|
76
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
77
|
+
|
78
|
+
var pf = new PageFactory();
|
79
|
+
pf.addEntryFourSquare(["Triangle", "Square", "Z", null]);
|
80
|
+
triangle_square_z_null = pf.compile();
|
81
|
+
|
82
|
+
var pf = new PageFactory();
|
83
|
+
pf.addEntryFourSquare(["Triangle", "Circle", null, "Q"]);
|
84
|
+
triangle_circle_null_q = pf.compile();
|
85
|
+
|
86
|
+
var pf = new PageFactory();
|
87
|
+
pf.addEntryFourSquare(["Triangle", "Circle", null, "Q"]);
|
88
|
+
triangle_circle_null_q = pf.compile();
|
89
|
+
|
90
|
+
var pf = new PageFactory();
|
91
|
+
pf.addEntryFourSquare(["Q", null, "Circle", "Square"]);
|
92
|
+
q_null_circle_square = pf.compile();
|
93
|
+
|
94
|
+
var pf = new PageFactory();
|
95
|
+
pf.addEntryFourSquare(["P", "Circle", null, "Q"]);
|
96
|
+
p_circle_null_q = pf.compile();
|
97
|
+
|
98
|
+
var pf = new PageFactory();
|
99
|
+
pf.addEntryFourSquare(["P", "Circle", null, null]);
|
100
|
+
p_circle_null_null = pf.compile();
|
101
|
+
|
102
|
+
var pf = new PageFactory();
|
103
|
+
pf.addEntryFourSquare(["P", null, null, "Q"]);
|
104
|
+
p_null_null_q = pf.compile();
|
105
|
+
|
106
|
+
var pf = new PageFactory();
|
107
|
+
pf.addEntryFourSquare(["P", "Square", null, null]);
|
108
|
+
p_square_null_null = pf.compile();
|
109
|
+
|
110
|
+
var pf = new PageFactory();
|
111
|
+
pf.addEntryFourSquare(["Triangle", null, "A", "M"]);
|
112
|
+
triangle_null_a_m = pf.compile();
|
113
|
+
|
114
|
+
var pf = new PageFactory();
|
115
|
+
pf.addEntryFourSquare(["Triangle", "Square", null, null]);
|
116
|
+
triangle_square_null_null = pf.compile();
|
117
|
+
|
118
|
+
var pf = new PageFactory();
|
119
|
+
pf.addEntryFourSquare(["Triangle", "Z", "Q", null]);
|
120
|
+
triangle_z_q_null = pf.compile();
|
121
|
+
|
122
|
+
var pf = new PageFactory(null);
|
123
|
+
head_null = pf.compile();
|
124
|
+
|
125
|
+
var pf = new PageFactory("world");
|
126
|
+
head_world = pf.compile();
|
127
|
+
|
128
|
+
var pf = new PageFactory(null);
|
129
|
+
next_null = pf.compile();
|
130
|
+
|
131
|
+
var pf = new PageFactory(null, "world");
|
132
|
+
next_world = pf.compile();
|
133
|
+
|
134
|
+
var pf = new PageFactory();
|
135
|
+
pf.addEntryFourSquareCustomIds([["id1", "Square"], ["id0", "Triangle"], ["id2", "Z"]]);
|
136
|
+
triangle_square_z_null_moved_square_triangle_z = pf.compile();
|
137
|
+
|
138
|
+
var pf = new PageFactory();
|
139
|
+
pf.addEntryFourSquareCustomIds([["id2", "Z"], ["id1", "Square"], ["id0", "Triangle"]]);
|
140
|
+
triangle_square_z_null_moved_z_square_triangle = pf.compile();
|
@@ -0,0 +1,150 @@
|
|
1
|
+
//Page Factor
|
2
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
3
|
+
function PageFactory(head, next) {
|
4
|
+
this.head = head;
|
5
|
+
this.next = next;
|
6
|
+
this.entries = [];
|
7
|
+
}
|
8
|
+
|
9
|
+
//Add an entry
|
10
|
+
PageFactory.prototype.addEntry = function(eid, value) {
|
11
|
+
this.entries.push({_id: eid, _sig: value, value: value});
|
12
|
+
}
|
13
|
+
|
14
|
+
//This adds up to four entrys that can be represented as a square:
|
15
|
+
//-------------
|
16
|
+
//| id0 | id1 |
|
17
|
+
//-------------
|
18
|
+
//| id2 | id3 |
|
19
|
+
//-------------
|
20
|
+
//Leaving out parts of the values array will not add those entries, e.g. ["Square", null, null, "Triangle"]
|
21
|
+
//--------------------|
|
22
|
+
//| Square | null |
|
23
|
+
//--------------------|
|
24
|
+
//| null | Triangle |
|
25
|
+
//--------------------|
|
26
|
+
//Where 'Square' is id0 and 'Triangle' is id3
|
27
|
+
PageFactory.prototype.addEntryFourSquare = function(values) {
|
28
|
+
if (values.length != 4) {
|
29
|
+
throw "FourSquare requires for values. Make values null if you don't need them"
|
30
|
+
}
|
31
|
+
|
32
|
+
for (var i = 0; i < values.length; ++i) {
|
33
|
+
if (values[i]) {
|
34
|
+
this.addEntry("id"+i, values[i]);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
//Same as addEntryFourSquare but takes an index parameter before the
|
40
|
+
//value that sets the id of each element
|
41
|
+
//e.g. addEntryFourSquareCustomIds([["id0, "A"], ["id2, "B"], ["id1, "C"], ["id3, "D"]]).
|
42
|
+
//[
|
43
|
+
// {_id: "id0", value: "A", _sig: "A"},
|
44
|
+
// {_id: "id3", value: "D", _sig: "D"},
|
45
|
+
// {_id: "id2", value: "C", _sig: "C"},
|
46
|
+
// {_id: "id1", value: "B", _sig: "B"},
|
47
|
+
//]
|
48
|
+
PageFactory.prototype.addEntryFourSquareCustomIds = function(values) {
|
49
|
+
for (var i = 0; i < values.length; ++i) {
|
50
|
+
//Get pair
|
51
|
+
var pair = values[i];
|
52
|
+
if (pair.length != 2) {
|
53
|
+
throw "FourSquareShuffle accepts pairs. E.g. ['id0', 'A']"
|
54
|
+
}
|
55
|
+
|
56
|
+
var id = pair[0];
|
57
|
+
var value = pair[1];
|
58
|
+
|
59
|
+
this.addEntry(id, value);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
//Returns a page
|
64
|
+
PageFactory.prototype.compile = function(page_id) {
|
65
|
+
if (page_id === undefined) {
|
66
|
+
var page = vm_create_page("default");
|
67
|
+
} else {
|
68
|
+
var page = vm_create_page(page_id);
|
69
|
+
}
|
70
|
+
|
71
|
+
page._head = this.head;
|
72
|
+
page._next = this.next;
|
73
|
+
|
74
|
+
page.entries = this.entries;
|
75
|
+
|
76
|
+
vm_rehash_page(page);
|
77
|
+
vm_reindex_page(page);
|
78
|
+
|
79
|
+
return page;
|
80
|
+
}
|
81
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
82
|
+
|
83
|
+
var pf = new PageFactory();
|
84
|
+
pf.addEntryFourSquare(["Triangle", "Square", "Z", null]);
|
85
|
+
triangle_square_z_null = pf.compile();
|
86
|
+
|
87
|
+
var pf = new PageFactory();
|
88
|
+
pf.addEntryFourSquare(["Triangle", "Circle", null, "Q"]);
|
89
|
+
triangle_circle_null_q = pf.compile();
|
90
|
+
|
91
|
+
var pf = new PageFactory();
|
92
|
+
pf.addEntryFourSquare(["Triangle", "Circle", null, "Q"]);
|
93
|
+
triangle_circle_null_q = pf.compile();
|
94
|
+
|
95
|
+
var pf = new PageFactory();
|
96
|
+
pf.addEntryFourSquare(["Q", null, "Circle", "Square"]);
|
97
|
+
q_null_circle_square = pf.compile();
|
98
|
+
|
99
|
+
var pf = new PageFactory();
|
100
|
+
pf.addEntryFourSquare(["P", "Circle", null, "Q"]);
|
101
|
+
p_circle_null_q = pf.compile();
|
102
|
+
|
103
|
+
var pf = new PageFactory();
|
104
|
+
pf.addEntryFourSquare(["P", "Circle", null, null]);
|
105
|
+
p_circle_null_null = pf.compile();
|
106
|
+
|
107
|
+
var pf = new PageFactory();
|
108
|
+
pf.addEntryFourSquare(["P", null, null, "Q"]);
|
109
|
+
p_null_null_q = pf.compile();
|
110
|
+
|
111
|
+
var pf = new PageFactory();
|
112
|
+
pf.addEntryFourSquare(["P", "Square", null, null]);
|
113
|
+
p_square_null_null = pf.compile();
|
114
|
+
|
115
|
+
var pf = new PageFactory();
|
116
|
+
pf.addEntryFourSquare(["Triangle", null, "A", "M"]);
|
117
|
+
triangle_null_a_m = pf.compile();
|
118
|
+
|
119
|
+
var pf = new PageFactory();
|
120
|
+
pf.addEntryFourSquare(["Triangle", "Square", null, null]);
|
121
|
+
triangle_square_null_null = pf.compile();
|
122
|
+
|
123
|
+
var pf = new PageFactory();
|
124
|
+
pf.addEntryFourSquare(["Triangle", "Z", "Q", null]);
|
125
|
+
triangle_z_q_null = pf.compile();
|
126
|
+
|
127
|
+
var pf = new PageFactory(null);
|
128
|
+
head_null = pf.compile();
|
129
|
+
|
130
|
+
var pf = new PageFactory("world");
|
131
|
+
head_world = pf.compile();
|
132
|
+
|
133
|
+
var pf = new PageFactory(null);
|
134
|
+
next_null = pf.compile();
|
135
|
+
|
136
|
+
var pf = new PageFactory(null, "world");
|
137
|
+
next_world = pf.compile();
|
138
|
+
|
139
|
+
var pf = new PageFactory();
|
140
|
+
pf.addEntryFourSquareCustomIds([["id1", "Square"], ["id0", "Triangle"], ["id2", "Z"]]);
|
141
|
+
triangle_square_z_null_moved_square_triangle_z = pf.compile();
|
142
|
+
|
143
|
+
var pf = new PageFactory();
|
144
|
+
pf.addEntryFourSquareCustomIds([["id2", "Z"], ["id1", "Square"], ["id0", "Triangle"]]);
|
145
|
+
triangle_square_z_null_moved_z_square_triangle = pf.compile();
|
146
|
+
|
147
|
+
//Seperate page
|
148
|
+
var pf = new PageFactory();
|
149
|
+
pf.addEntryFourSquare(["P", "Square", null, null]);
|
150
|
+
default2_square_null_null = pf.compile("default2");
|
@@ -596,6 +596,25 @@ RSpec.describe "kern:controller_spec" do
|
|
596
596
|
@driver.mexpect("if_event", [base, "context", {"base" => base, "secret" => "foo"}])
|
597
597
|
end
|
598
598
|
|
599
|
+
it "Does allow service macros in the global on_entry function" do
|
600
|
+
#Compile the controller
|
601
|
+
ctx = flok_new_user File.read('./spec/kern/assets/global_on_entry5.rb'), File.read("./spec/kern/assets/vm/config5.rb")
|
602
|
+
|
603
|
+
#Run the embed function
|
604
|
+
secret = SecureRandom.hex
|
605
|
+
ctx.eval %{
|
606
|
+
global_on_entry_called_count = 0;
|
607
|
+
|
608
|
+
//Call embed on main root view
|
609
|
+
base = _embed("my_controller", 0, {}, null);
|
610
|
+
|
611
|
+
int_dispatch([]);
|
612
|
+
}
|
613
|
+
|
614
|
+
expect(ctx.eval("read_res_called")).to eq(true)
|
615
|
+
end
|
616
|
+
|
617
|
+
|
599
618
|
it "Does allow interval (every) events" do
|
600
619
|
#Compile the controller
|
601
620
|
ctx = flok_new_user File.read('./spec/kern/assets/interval.rb')
|
@@ -0,0 +1,1111 @@
|
|
1
|
+
#This contains tests for the 'functions' of the vm service system
|
2
|
+
|
3
|
+
Dir.chdir File.join File.dirname(__FILE__), '../../'
|
4
|
+
require './spec/env/kern.rb'
|
5
|
+
require './spec/lib/helpers.rb'
|
6
|
+
require './spec/lib/io_extensions.rb'
|
7
|
+
require './spec/lib/rspec_extensions.rb'
|
8
|
+
require 'zlib'
|
9
|
+
|
10
|
+
#Evaluates the
|
11
|
+
def eval_and_dump str
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.describe "kern:vm_service_functional" do
|
16
|
+
include Zlib
|
17
|
+
include_context "kern"
|
18
|
+
|
19
|
+
it "Can can use vm_create_page" do
|
20
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config5.rb")
|
21
|
+
dump = ctx.evald %{
|
22
|
+
dump.new_page = vm_create_page("my_id")
|
23
|
+
dump.new_anon_page = vm_create_page();
|
24
|
+
}
|
25
|
+
|
26
|
+
expect(dump["new_page"]).to eq({
|
27
|
+
"_head" => nil,
|
28
|
+
"_next" => nil,
|
29
|
+
"_id" => "my_id",
|
30
|
+
"entries" => [],
|
31
|
+
"__index" => {},
|
32
|
+
"_hash" => nil,
|
33
|
+
})
|
34
|
+
|
35
|
+
expect(dump["new_anon_page"]["_id"]).not_to eq nil
|
36
|
+
expect(dump["new_anon_page"]["entries"]).to eq []
|
37
|
+
end
|
38
|
+
|
39
|
+
it "Can can use vm_copy_page" do
|
40
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config5.rb")
|
41
|
+
dump = ctx.evald %{
|
42
|
+
dump.new_page = vm_create_page("Q")
|
43
|
+
dump.no_head_no_next_no_entry = vm_copy_page(dump.new_page);
|
44
|
+
|
45
|
+
//Modify the new_page with a head, next, and entry; then create a copy
|
46
|
+
dump.new_page._head = "Z";
|
47
|
+
dump.new_page._next = "Triangle";
|
48
|
+
dump.new_page.entries.push({"_id": "id0", "_sig": "Square", "value": "Square"});
|
49
|
+
dump.head_z_next_triangle_entry_square = vm_copy_page(dump.new_page);
|
50
|
+
|
51
|
+
//Modify the new_page's entry in-place and make a copy
|
52
|
+
dump.new_page.entries[0]["_sig"] = "Circle";
|
53
|
+
dump.new_page.entries[0]["value"] = "Circle";
|
54
|
+
dump.head_z_next_triangle_entry_circle = vm_copy_page(dump.new_page);
|
55
|
+
|
56
|
+
//Modify the new_page's entry again in-place
|
57
|
+
dump.new_page.entries[0]["_sig"] = "Triangle"
|
58
|
+
dump.new_page.entries[0]["value"] = "Triangle"
|
59
|
+
}
|
60
|
+
|
61
|
+
expect(dump["no_head_no_next_no_entry"]).to eq({
|
62
|
+
"_head" => nil,
|
63
|
+
"_next" => nil,
|
64
|
+
"_id" => "Q",
|
65
|
+
"_hash" => nil,
|
66
|
+
"entries" => [],
|
67
|
+
})
|
68
|
+
|
69
|
+
expect(dump["head_z_next_triangle_entry_square"]).to eq({
|
70
|
+
"_head" => "Z",
|
71
|
+
"_next" => "Triangle",
|
72
|
+
"_id" => "Q",
|
73
|
+
"_hash" => nil,
|
74
|
+
"entries" => [
|
75
|
+
{"_id" => "id0", "_sig" => "Square", "value" => "Square"},
|
76
|
+
],
|
77
|
+
})
|
78
|
+
|
79
|
+
expect(dump["head_z_next_triangle_entry_circle"]).to eq({
|
80
|
+
"_head" => "Z",
|
81
|
+
"_next" => "Triangle",
|
82
|
+
"_id" => "Q",
|
83
|
+
"_hash" => nil,
|
84
|
+
"entries" => [
|
85
|
+
{"_id" => "id0", "_sig" => "Circle", "value" => "Circle"},
|
86
|
+
],
|
87
|
+
})
|
88
|
+
|
89
|
+
expect(dump["new_page"]).to eq({
|
90
|
+
"_head" => "Z",
|
91
|
+
"_next" => "Triangle",
|
92
|
+
"_id" => "Q",
|
93
|
+
"_hash" => nil,
|
94
|
+
"entries" => [
|
95
|
+
{"_id" => "id0", "_sig" => "Triangle", "value" => "Triangle"},
|
96
|
+
],
|
97
|
+
"__index" => {}
|
98
|
+
})
|
99
|
+
end
|
100
|
+
|
101
|
+
#vm_rehash_page
|
102
|
+
###########################################################################
|
103
|
+
it "vm_rehash_page can calculate the hash correctly" do
|
104
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config3.rb")
|
105
|
+
|
106
|
+
#Run the check
|
107
|
+
res = ctx.eval %{
|
108
|
+
//Manually construct a page
|
109
|
+
var page = {
|
110
|
+
_head: null,
|
111
|
+
_next: null,
|
112
|
+
_id: "hello",
|
113
|
+
entries: [
|
114
|
+
{_id: "hello2", _sig: "nohteunth"},
|
115
|
+
]
|
116
|
+
}
|
117
|
+
|
118
|
+
vm_rehash_page(page);
|
119
|
+
}
|
120
|
+
|
121
|
+
#Calculate hash ourselves
|
122
|
+
hash = crc32("hello")
|
123
|
+
hash = crc32("nohteunth", hash)
|
124
|
+
page = JSON.parse(ctx.eval("JSON.stringify(page)"))
|
125
|
+
page = JSON.parse(ctx.eval("JSON.stringify(page)"))
|
126
|
+
|
127
|
+
#Expect the same hash
|
128
|
+
expect(page).to eq({
|
129
|
+
"_head" => nil,
|
130
|
+
"_next" => nil,
|
131
|
+
"_id" => "hello",
|
132
|
+
"entries" => [
|
133
|
+
{"_id" => "hello2", "_sig" => "nohteunth"}
|
134
|
+
],
|
135
|
+
"_hash" => hash.to_s
|
136
|
+
})
|
137
|
+
end
|
138
|
+
|
139
|
+
it "vm_rehash_page can calculate the hash correctly with head and next" do
|
140
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config3.rb")
|
141
|
+
|
142
|
+
#Run the check
|
143
|
+
res = ctx.eval %{
|
144
|
+
//Manually construct a page
|
145
|
+
var page = {
|
146
|
+
_head: "a",
|
147
|
+
_next: "b",
|
148
|
+
_id: "hello",
|
149
|
+
entries: [
|
150
|
+
{_id: "hello2", _sig: "nohteunth"},
|
151
|
+
]
|
152
|
+
}
|
153
|
+
|
154
|
+
vm_rehash_page(page);
|
155
|
+
}
|
156
|
+
|
157
|
+
#Calculate hash ourselves
|
158
|
+
hash = crc32("a")
|
159
|
+
hash = crc32("b", hash)
|
160
|
+
hash = crc32("hello", hash)
|
161
|
+
hash = crc32("nohteunth", hash)
|
162
|
+
page = JSON.parse(ctx.eval("JSON.stringify(page)"))
|
163
|
+
|
164
|
+
#Expect the same hash
|
165
|
+
expect(page).to eq({
|
166
|
+
"_head" => "a",
|
167
|
+
"_next" => "b",
|
168
|
+
"_id" => "hello",
|
169
|
+
"entries" => [
|
170
|
+
{"_id" => "hello2", "_sig" => "nohteunth"}
|
171
|
+
],
|
172
|
+
"_hash" => hash.to_s
|
173
|
+
})
|
174
|
+
end
|
175
|
+
###########################################################################
|
176
|
+
|
177
|
+
#vm_reindex_page
|
178
|
+
###########################################################################
|
179
|
+
it "vm_reindex_page can calculate the __index correctly" do
|
180
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller0.rb'), File.read("./spec/kern/assets/vm/config3.rb")
|
181
|
+
|
182
|
+
#Run the check
|
183
|
+
res = ctx.eval %{
|
184
|
+
//Manually construct a page
|
185
|
+
var page = {
|
186
|
+
_head: null,
|
187
|
+
_next: null,
|
188
|
+
_id: "hello",
|
189
|
+
entries: [
|
190
|
+
{_id: "hello2", _sig: "nohteunth"},
|
191
|
+
{_id: "hello3", _sig: "nohteunth2"},
|
192
|
+
]
|
193
|
+
}
|
194
|
+
|
195
|
+
vm_reindex_page(page);
|
196
|
+
}
|
197
|
+
|
198
|
+
#Expect the same hash
|
199
|
+
page = ctx.dump("page")
|
200
|
+
expect(page.keys).to include("__index")
|
201
|
+
expect(page["__index"]).to eq({
|
202
|
+
"hello2" => 0,
|
203
|
+
"hello3" => 1
|
204
|
+
})
|
205
|
+
end
|
206
|
+
###########################################################################
|
207
|
+
|
208
|
+
#vm_diff
|
209
|
+
###########################################################################
|
210
|
+
|
211
|
+
#################################################################################################################
|
212
|
+
#Each vm_diff_entry is any array in the format of [type, *args] and each matcher is a hash
|
213
|
+
#in the format of {:type => "*", :args => [...]}. In order for a matcher to match a vm_diff_entry
|
214
|
+
#the matcher's :type must be equal to the vm_diff_entry's type, and the matcher's :args must be
|
215
|
+
#equal to the vm_diff_entry's *args. Equivalency for type is defined as absolutely equal. Equivalency
|
216
|
+
#for args is defined per element; in order for args to be equivalent, all elements of the args must
|
217
|
+
#be equivalent. Each element must be absolutely equal to be equivalent with the exception of argument
|
218
|
+
#elements where the matcher element is of type hash. In the hash case, equivalency is true if the vm_diff_entry
|
219
|
+
#sibling argument element is of type hash *and* the sibling element contains at-least all the key-value pairs
|
220
|
+
#in the forementioned matcher's arg element.
|
221
|
+
#e.g.
|
222
|
+
#################################################################################################################
|
223
|
+
#1. Match without a matcher's args element of type hash.
|
224
|
+
# ["foo", "bar", 3] <=> {:type => "foo", :args => ["bar", 3]}
|
225
|
+
#2. Match with a matcher's args element of type hash.
|
226
|
+
# ["foo", "bar", {"hello" => "world", "goodbye" => "world} <=> {:type => "foo", :args => [{"hello" => "world"}]}
|
227
|
+
#################################################################################################################
|
228
|
+
def verify_vm_diff vm_diff, matchers
|
229
|
+
winning_candidates = []
|
230
|
+
|
231
|
+
_vm_diff = JSON.parse(vm_diff.to_json)
|
232
|
+
|
233
|
+
_vm_diff.each do |vm_diff_entry|
|
234
|
+
#Get the vm_diff_entry in the format of [type, *args]
|
235
|
+
type = vm_diff_entry.shift
|
236
|
+
args = vm_diff_entry
|
237
|
+
|
238
|
+
#Find candidate matchers that have the same type as the vm_diff_entry
|
239
|
+
candidates = matchers.select{|e| e[:type] == type}
|
240
|
+
raise "verify_vm_diff failed. The given vm_diff contained a type, #{type.inspect} that was not even mentioned in the matchers. \nvm_diff = #{vm_diff.inspect}, \nmatchers = #{matchers.inspect}" unless candidates.length > 0
|
241
|
+
|
242
|
+
#Find a candidate that matches the args rules listed in the comments
|
243
|
+
winning_candidate = nil
|
244
|
+
candidates.each do |c|
|
245
|
+
catch(:candidate_failed) do
|
246
|
+
raise "verify_vm_diff failed. A given matcher with type, \n#{c[:type]}, \ncontained no :args array" unless c[:args]
|
247
|
+
next unless c[:args].length == args.length
|
248
|
+
|
249
|
+
c[:args].each_with_index do |a, i|
|
250
|
+
if a.class == Hash
|
251
|
+
throw :candidate_failed if args[i].class != Hash
|
252
|
+
a.each do |k, v|
|
253
|
+
throw :candidate_failed if args[i][k] != v
|
254
|
+
end
|
255
|
+
else
|
256
|
+
#Everything else is exactly equal to be equivalent
|
257
|
+
throw :candidate_failed if a != args[i]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
winning_candidate = c
|
262
|
+
break
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
if winning_candidate
|
267
|
+
winning_candidates << winning_candidate
|
268
|
+
else
|
269
|
+
raise "verify_vm_diff failed. Could not find a candidate to match the vm_diff_entry of: #{[type, *args]} with the matchers of #{matchers.inspect}"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
#Make sure all matchers were used
|
274
|
+
left_matchers = matchers - winning_candidates
|
275
|
+
raise "verify_vm_diff failed. Matchers did not all match a vm_diff_entry. \nRemaining matchers include \n#{left_matchers.inspect} \nand matched matchers include \n#{winning_candidates.inspect}\n for the vm_diff of\n#{vm_diff.inspect}" if left_matchers.length > 0
|
276
|
+
end
|
277
|
+
|
278
|
+
#Each vm_page["entries"] is an array, this helper function allows you to define a set
|
279
|
+
#of matchers which will check the entries array to verify that all matchers are equal to
|
280
|
+
#one unique element of the vm_page["entries"]. If all matchers are not exahusted, or all
|
281
|
+
#vm_page["entries"] do not have a paired matcher, then this verify function fails. Equivalency
|
282
|
+
#for entry matcher implies that all key-value pairs of the matcher are present in a vm_page["entries"] entry.
|
283
|
+
#e.g.
|
284
|
+
#############################################################################################################
|
285
|
+
#Matching entry & matcher pair
|
286
|
+
#entry = {"_id" => "my_id", "value" => 4}
|
287
|
+
#matcher = {"_id" => "my_id"} or {"value" => 4} or {"_id => "my_id", "value" => 4}
|
288
|
+
#############################################################################################################
|
289
|
+
def verify_vm_page_entries page, matchers
|
290
|
+
matching_matchers = []
|
291
|
+
page["entries"].each do |entry|
|
292
|
+
#Find matching matcher from matchers
|
293
|
+
matching_matcher = nil
|
294
|
+
matchers.each do |matcher|
|
295
|
+
catch(:matcher_does_not_match) do
|
296
|
+
#For all key value pairs in matcher
|
297
|
+
matcher.each do |k, v|
|
298
|
+
throw :matcher_does_not_match if entry[k] != v
|
299
|
+
end
|
300
|
+
|
301
|
+
matching_matcher = matcher
|
302
|
+
break
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
if matching_matcher
|
307
|
+
matching_matchers << matching_matcher
|
308
|
+
else
|
309
|
+
raise "verify_vm_page_entries failed: The entry: #{entry.inspect} had no matchers that would fit the bill, given matchers include: #{matchers.inspect}. The page was: #{page.inspect}"
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
left_matchers = matchers - matching_matchers
|
314
|
+
raise "verify_vm_page_entries failed: Matchers did not all match an entry. \nRemaining matchers include\n#{left_matchers.inspect}\n and matched matchers include \n#{matching_matchers.inspect}\n for the page of #{page.inspect}" if left_matchers.length > 0
|
315
|
+
end
|
316
|
+
|
317
|
+
#Same as verify_vm_page_entries, but the order of the matchers is taken into account
|
318
|
+
def verify_vm_page_entries_with_order page, matchers
|
319
|
+
page["entries"].each_with_index do |entry, i|
|
320
|
+
matcher = matchers[i]
|
321
|
+
|
322
|
+
#Matcher should match all k, v pairs
|
323
|
+
matcher.each do |k, v|
|
324
|
+
raise "Matcher #{matcher.inspect} did not match entry: #{entry.inspect}\n The order was taken into consideration for entries:\n#{page["entries"].inspect}\nWith Matchers\n#{matchers.inspect}" if entry[k] != v
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
#Reload the vm_diff_pages.js. Needed because vm_diff functions
|
331
|
+
#are often destructive and multiple tests need to have a fresh
|
332
|
+
#copy of the pages
|
333
|
+
def reload_vm_diff_pages(ctx)
|
334
|
+
pages_src = File.read("./spec/kern/assets/vm/vm_diff_pages.js")
|
335
|
+
ctx.eval pages_src
|
336
|
+
end
|
337
|
+
|
338
|
+
it "can use vm_diff" do
|
339
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller22.rb'), File.read("./spec/kern/assets/vm/config5.rb")
|
340
|
+
|
341
|
+
#diff of vm_commit:0, 1
|
342
|
+
#| Triangle | Square | -> | Triangle | Circle |
|
343
|
+
#| K | | -> | | Q |
|
344
|
+
#from to
|
345
|
+
reload_vm_diff_pages(ctx)
|
346
|
+
dump = ctx.evald %{
|
347
|
+
var from = triangle_square_z_null;
|
348
|
+
var to = triangle_circle_null_q;
|
349
|
+
dump.diff = vm_diff(from, to)
|
350
|
+
vm_diff_replay(from, dump.diff);
|
351
|
+
dump.replay = from;
|
352
|
+
vm_rehash_page(dump.replay);
|
353
|
+
vm_reindex_page(dump.replay);
|
354
|
+
}
|
355
|
+
verify_vm_diff(dump["diff"], [
|
356
|
+
{type: "M", args: [{"_id" => "id1", "value" => "Circle"}]},
|
357
|
+
{type: "-", args: ["id2"]},
|
358
|
+
{type: "+", args: [2, {"_id" => "id3", "value" => "Q"}]}
|
359
|
+
])
|
360
|
+
verify_vm_page_entries(dump["replay"], [
|
361
|
+
{"_id" => "id0", "value" => "Triangle"},
|
362
|
+
{"_id" => "id1", "value" => "Circle"},
|
363
|
+
{"_id" => "id3", "value" => "Q"},
|
364
|
+
])
|
365
|
+
|
366
|
+
#vm_commit:2
|
367
|
+
#| Triangle | Square | -> | Q | |
|
368
|
+
#| K | | -> | Circle | Square |
|
369
|
+
#from to
|
370
|
+
reload_vm_diff_pages(ctx)
|
371
|
+
dump = ctx.evald %{
|
372
|
+
var from = triangle_square_z_null;
|
373
|
+
var to = q_null_circle_square;
|
374
|
+
dump.diff = vm_diff(from, to)
|
375
|
+
vm_diff_replay(from, dump.diff);
|
376
|
+
dump.replay = from;
|
377
|
+
vm_rehash_page(dump.replay);
|
378
|
+
vm_reindex_page(dump.replay);
|
379
|
+
}
|
380
|
+
verify_vm_diff(dump["diff"], [
|
381
|
+
{type: "M", args: [{"_id" => "id0", "value" => "Q"}]},
|
382
|
+
{type: "-", args: ["id1"]},
|
383
|
+
{type: "M", args: [{"_id" => "id2", "value" => "Circle"}]},
|
384
|
+
{type: "+", args: [2, {"_id" => "id3", "value" => "Square"}]}
|
385
|
+
])
|
386
|
+
verify_vm_page_entries(dump["replay"], [
|
387
|
+
{"_id" => "id0", "value" => "Q"},
|
388
|
+
{"_id" => "id2", "value" => "Circle"},
|
389
|
+
{"_id" => "id3", "value" => "Square"},
|
390
|
+
])
|
391
|
+
|
392
|
+
#vm_rebase:1 (diff only)
|
393
|
+
#| P | Circle | -> | P | Circle |
|
394
|
+
#| | Q | -> | | |
|
395
|
+
#from to
|
396
|
+
reload_vm_diff_pages(ctx)
|
397
|
+
dump = ctx.evald %{
|
398
|
+
var from = p_circle_null_q;
|
399
|
+
dump.diff = [
|
400
|
+
["+", 0, {"_id": "id1", "_sig": "Square", "value": "Square"}],
|
401
|
+
["M", {"_id": "id2", "_sig": "Z", "value": "Z"}],
|
402
|
+
["-", "id3"],
|
403
|
+
]
|
404
|
+
vm_diff_replay(from, dump.diff);
|
405
|
+
dump.replay = from;
|
406
|
+
vm_rehash_page(dump.replay);
|
407
|
+
vm_reindex_page(dump.replay);
|
408
|
+
}
|
409
|
+
verify_vm_page_entries(dump["replay"], [
|
410
|
+
{"_id" => "id0", "value" => "P"},
|
411
|
+
{"_id" => "id1", "value" => "Circle"},
|
412
|
+
])
|
413
|
+
|
414
|
+
#vm_rebase:2a (diff only)
|
415
|
+
#| P | Circle | -> | P | |
|
416
|
+
#| | Q | -> | | Q |
|
417
|
+
#from to
|
418
|
+
reload_vm_diff_pages(ctx)
|
419
|
+
dump = ctx.evald %{
|
420
|
+
var from = p_circle_null_q;
|
421
|
+
dump.diff = [
|
422
|
+
["-", "id1"],
|
423
|
+
["M", {"_id": "id2", "_sig": "A", "value": "A"}],
|
424
|
+
["+", 2, {"_id":"id3", "_sig": "M", "value": "M"}],
|
425
|
+
]
|
426
|
+
vm_diff_replay(from, dump.diff);
|
427
|
+
dump.replay = from;
|
428
|
+
vm_rehash_page(dump.replay);
|
429
|
+
vm_reindex_page(dump.replay);
|
430
|
+
}
|
431
|
+
verify_vm_page_entries(dump["replay"], [
|
432
|
+
{"_id" => "id0", "value" => "P"},
|
433
|
+
{"_id" => "id3", "value" => "Q"},
|
434
|
+
])
|
435
|
+
|
436
|
+
#vm_rebase:2b (diff only)
|
437
|
+
#| P | | -> | P | Square |
|
438
|
+
#| | Q | -> | | |
|
439
|
+
#from to
|
440
|
+
reload_vm_diff_pages(ctx)
|
441
|
+
dump = ctx.evald %{
|
442
|
+
var from = p_null_null_q;
|
443
|
+
dump.diff = [
|
444
|
+
["+", 1, {"_id":"id1", "_sig": "Square", "value": "Square"}],
|
445
|
+
["M", {"_id": "id2", "_sig": "Z", "value": "Z"}],
|
446
|
+
["-", "id3"],
|
447
|
+
]
|
448
|
+
vm_diff_replay(from, dump.diff);
|
449
|
+
dump.replay = from;
|
450
|
+
vm_rehash_page(dump.replay);
|
451
|
+
vm_reindex_page(dump.replay);
|
452
|
+
}
|
453
|
+
verify_vm_page_entries(dump["replay"], [
|
454
|
+
{"_id" => "id0", "value" => "P"},
|
455
|
+
{"_id" => "id1", "value" => "Square"},
|
456
|
+
])
|
457
|
+
|
458
|
+
#vm_rebase:2c
|
459
|
+
#| P | | -> | P | Square |
|
460
|
+
#| | Q | -> | | |
|
461
|
+
#from to
|
462
|
+
reload_vm_diff_pages(ctx)
|
463
|
+
dump = ctx.evald %{
|
464
|
+
var from = p_null_null_q;
|
465
|
+
var to = p_square_null_null;
|
466
|
+
dump.diff = vm_diff(from, to)
|
467
|
+
vm_diff_replay(from, dump.diff);
|
468
|
+
dump.replay = from;
|
469
|
+
vm_rehash_page(dump.replay);
|
470
|
+
vm_reindex_page(dump.replay);
|
471
|
+
}
|
472
|
+
verify_vm_diff(dump["diff"], [
|
473
|
+
{type: "+", args: [1, {"_id" => "id1", "value" => "Square"}]},
|
474
|
+
{type: "-", args: ["id3"]},
|
475
|
+
])
|
476
|
+
verify_vm_page_entries(dump["replay"], [
|
477
|
+
{"_id" => "id0", "value" => "P"},
|
478
|
+
{"_id" => "id1", "value" => "Square"},
|
479
|
+
])
|
480
|
+
|
481
|
+
#vm_rebase:2d
|
482
|
+
#| Triangle | | -> | Triangle | Square |
|
483
|
+
#| A | M | -> | Z | |
|
484
|
+
#from to
|
485
|
+
reload_vm_diff_pages(ctx)
|
486
|
+
dump = ctx.evald %{
|
487
|
+
var from = triangle_null_a_m;
|
488
|
+
var to = triangle_square_z_null;
|
489
|
+
dump.diff = vm_diff(from, to)
|
490
|
+
vm_diff_replay(from, dump.diff);
|
491
|
+
dump.replay = from;
|
492
|
+
vm_rehash_page(dump.replay);
|
493
|
+
vm_reindex_page(dump.replay);
|
494
|
+
}
|
495
|
+
verify_vm_diff(dump["diff"], [
|
496
|
+
{type: "+", args: [1, {"_id" => "id1", "value" => "Square"}]},
|
497
|
+
{type: "M", args: [{"_id" => "id2", "value" => "Z"}]},
|
498
|
+
{type: "-", args: ["id3"]},
|
499
|
+
])
|
500
|
+
verify_vm_page_entries(dump["replay"], [
|
501
|
+
{"_id" => "id0", "value" => "Triangle"},
|
502
|
+
{"_id" => "id1", "value" => "Square"},
|
503
|
+
{"_id" => "id2", "value" => "Z"},
|
504
|
+
])
|
505
|
+
|
506
|
+
#vm_addendum:2a (diff only)
|
507
|
+
#| Triangle | Square | -> | Triangle | Z |
|
508
|
+
#| | | -> | Q | |
|
509
|
+
#from to
|
510
|
+
reload_vm_diff_pages(ctx)
|
511
|
+
dump = ctx.evald %{
|
512
|
+
var from = triangle_square_null_null;
|
513
|
+
dump.diff = [
|
514
|
+
["M", {"_id": "id1", "_sig": "Z", "value": "Z"}],
|
515
|
+
["+", 2, {"_id":"id2", "_sig": "Q", "value": "Q"}],
|
516
|
+
["-", "id3"],
|
517
|
+
]
|
518
|
+
vm_diff_replay(from, dump.diff);
|
519
|
+
dump.replay = from;
|
520
|
+
vm_rehash_page(dump.replay);
|
521
|
+
vm_reindex_page(dump.replay);
|
522
|
+
}
|
523
|
+
verify_vm_page_entries(dump["replay"], [
|
524
|
+
{"_id" => "id0", "value" => "Triangle"},
|
525
|
+
{"_id" => "id1", "value" => "Z"},
|
526
|
+
{"_id" => "id2", "value" => "Q"},
|
527
|
+
])
|
528
|
+
|
529
|
+
#vm_addendum:2b (diff only)
|
530
|
+
#| Triangle | Square | -> | Triangle | Z |
|
531
|
+
#| | | -> | Q | |
|
532
|
+
#from to
|
533
|
+
reload_vm_diff_pages(ctx)
|
534
|
+
dump = ctx.evald %{
|
535
|
+
var from = triangle_square_null_null;
|
536
|
+
dump.diff = [
|
537
|
+
["M", {"_id": "id1", "_sig": "Z", "value": "Z"}],
|
538
|
+
["+", 2, {"_id":"id2", "_sig": "Q", "value": "Q"}],
|
539
|
+
["-", "id3"],
|
540
|
+
]
|
541
|
+
vm_diff_replay(from, dump.diff);
|
542
|
+
dump.replay = from;
|
543
|
+
vm_rehash_page(dump.replay);
|
544
|
+
vm_reindex_page(dump.replay);
|
545
|
+
}
|
546
|
+
verify_vm_page_entries(dump["replay"], [
|
547
|
+
{"_id" => "id0", "value" => "Triangle"},
|
548
|
+
{"_id" => "id1", "value" => "Z"},
|
549
|
+
{"_id" => "id2", "value" => "Q"},
|
550
|
+
])
|
551
|
+
|
552
|
+
#vm_addendum:2c
|
553
|
+
#head:null head:world
|
554
|
+
#from to
|
555
|
+
reload_vm_diff_pages(ctx)
|
556
|
+
dump = ctx.evald %{
|
557
|
+
var from = head_null;
|
558
|
+
var to = head_world;
|
559
|
+
dump.diff = vm_diff(from, to)
|
560
|
+
vm_diff_replay(from, dump.diff);
|
561
|
+
dump.replay = from;
|
562
|
+
vm_rehash_page(dump.replay);
|
563
|
+
vm_reindex_page(dump.replay);
|
564
|
+
}
|
565
|
+
verify_vm_diff(dump["diff"], [
|
566
|
+
{type: "HEAD_M", args: ["world"]}
|
567
|
+
])
|
568
|
+
expect(dump["replay"]["_head"]).to eq("world")
|
569
|
+
|
570
|
+
#vm_addendum:2d
|
571
|
+
#head:world head:null
|
572
|
+
#from to
|
573
|
+
reload_vm_diff_pages(ctx)
|
574
|
+
dump = ctx.evald %{
|
575
|
+
var from = head_world;
|
576
|
+
var to = head_null;
|
577
|
+
dump.diff = vm_diff(from, to)
|
578
|
+
vm_diff_replay(from, dump.diff);
|
579
|
+
dump.replay = from;
|
580
|
+
vm_rehash_page(dump.replay);
|
581
|
+
vm_reindex_page(dump.replay);
|
582
|
+
}
|
583
|
+
verify_vm_diff(dump["diff"], [
|
584
|
+
{type: "HEAD_M", args: [nil]}
|
585
|
+
])
|
586
|
+
expect(dump["replay"]["_head"]).to eq(nil)
|
587
|
+
|
588
|
+
#vm_addendum:2e
|
589
|
+
#next:null next:world
|
590
|
+
#from to
|
591
|
+
reload_vm_diff_pages(ctx)
|
592
|
+
dump = ctx.evald %{
|
593
|
+
var from = next_null;
|
594
|
+
var to = next_world;
|
595
|
+
dump.diff = vm_diff(from, to)
|
596
|
+
vm_diff_replay(from, dump.diff);
|
597
|
+
dump.replay = from;
|
598
|
+
vm_rehash_page(dump.replay);
|
599
|
+
vm_reindex_page(dump.replay);
|
600
|
+
}
|
601
|
+
verify_vm_diff(dump["diff"], [
|
602
|
+
{type: "NEXT_M", args: ["world"]}
|
603
|
+
])
|
604
|
+
expect(dump["replay"]["_next"]).to eq("world")
|
605
|
+
|
606
|
+
#vm_addendum:2f
|
607
|
+
#next:world next:null
|
608
|
+
#from to
|
609
|
+
reload_vm_diff_pages(ctx)
|
610
|
+
dump = ctx.evald %{
|
611
|
+
var from = next_world;
|
612
|
+
var to = next_null;
|
613
|
+
dump.diff = vm_diff(from, to)
|
614
|
+
vm_diff_replay(from, dump.diff);
|
615
|
+
dump.replay = from;
|
616
|
+
vm_rehash_page(dump.replay);
|
617
|
+
vm_reindex_page(dump.replay);
|
618
|
+
}
|
619
|
+
verify_vm_diff(dump["diff"], [
|
620
|
+
{type: "NEXT_M", args: [nil]}
|
621
|
+
])
|
622
|
+
expect(dump["replay"]["_next"]).to eq(nil)
|
623
|
+
|
624
|
+
#continued... moved, XXXXXXX(N) is the new index
|
625
|
+
#| Triangle(0) | Square(1)| -> | Triangle(1)| Square(0)|
|
626
|
+
#| Z(2) | | -> | Z(2) | |
|
627
|
+
#from to
|
628
|
+
reload_vm_diff_pages(ctx)
|
629
|
+
dump = ctx.evald %{
|
630
|
+
var from = triangle_square_z_null;
|
631
|
+
var to = triangle_square_z_null_moved_square_triangle_z;
|
632
|
+
dump.diff = vm_diff(from, to)
|
633
|
+
vm_diff_replay(from, dump.diff);
|
634
|
+
dump.replay = from;
|
635
|
+
vm_rehash_page(dump.replay);
|
636
|
+
vm_reindex_page(dump.replay);
|
637
|
+
}
|
638
|
+
verify_vm_diff(dump["diff"], [
|
639
|
+
{type: ">", args: [1, "id0"]}
|
640
|
+
])
|
641
|
+
verify_vm_page_entries_with_order(dump["replay"], [
|
642
|
+
{"_id" => "id1", "value" => "Square"},
|
643
|
+
{"_id" => "id0", "value" => "Triangle"},
|
644
|
+
{"_id" => "id2", "value" => "Z"},
|
645
|
+
])
|
646
|
+
|
647
|
+
#moved(2)
|
648
|
+
#| Triangle(0) | Square(1)| -> | Triangle(2)| Square(1)|
|
649
|
+
#| Z(2) | | -> | Z(0) | |
|
650
|
+
#from to
|
651
|
+
reload_vm_diff_pages(ctx)
|
652
|
+
dump = ctx.evald %{
|
653
|
+
var from = triangle_square_z_null;
|
654
|
+
var to = triangle_square_z_null_moved_z_square_triangle;
|
655
|
+
dump.diff = vm_diff(from, to)
|
656
|
+
vm_diff_replay(from, dump.diff);
|
657
|
+
dump.replay = from;
|
658
|
+
vm_rehash_page(dump.replay);
|
659
|
+
vm_reindex_page(dump.replay);
|
660
|
+
}
|
661
|
+
verify_vm_diff(dump["diff"], [
|
662
|
+
{type: ">", args: [2, "id0"]},
|
663
|
+
{type: ">", args: [1, "id1"]}
|
664
|
+
])
|
665
|
+
verify_vm_page_entries_with_order(dump["replay"], [
|
666
|
+
{"_id" => "id2", "value" => "Z"},
|
667
|
+
{"_id" => "id1", "value" => "Square"},
|
668
|
+
{"_id" => "id0", "value" => "Triangle"},
|
669
|
+
])
|
670
|
+
|
671
|
+
#moved(3) Not taking a diff, presenting an illegal move diff
|
672
|
+
#to use on Q (Which dosen't exist)
|
673
|
+
#| Triangle(0) | Square(1)| -> | Triangle(2)| Square(1)|
|
674
|
+
#| Z(2) | | -> | Z(0) | |
|
675
|
+
#from to
|
676
|
+
reload_vm_diff_pages(ctx)
|
677
|
+
dump = ctx.evald %{
|
678
|
+
var from = triangle_square_z_null;
|
679
|
+
dump.diff = [
|
680
|
+
[">", 3, "id3"],
|
681
|
+
[">", 2, "id0"],
|
682
|
+
[">", 1, "id1"],
|
683
|
+
]
|
684
|
+
vm_diff_replay(from, dump.diff);
|
685
|
+
dump.replay = from;
|
686
|
+
vm_rehash_page(dump.replay);
|
687
|
+
vm_reindex_page(dump.replay);
|
688
|
+
}
|
689
|
+
verify_vm_page_entries_with_order(dump["replay"], [
|
690
|
+
{"_id" => "id2", "value" => "Z"},
|
691
|
+
{"_id" => "id1", "value" => "Square"},
|
692
|
+
{"_id" => "id0", "value" => "Triangle"},
|
693
|
+
])
|
694
|
+
end
|
695
|
+
###########################################################################
|
696
|
+
|
697
|
+
#vm commit helpers
|
698
|
+
###########################################################################
|
699
|
+
def reload_vm_commit_pages(ctx)
|
700
|
+
pages_src = File.read("./spec/kern/assets/vm/vm_commit_pages.js")
|
701
|
+
ctx.eval pages_src
|
702
|
+
end
|
703
|
+
|
704
|
+
it "can use vm_commit" do
|
705
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller22.rb'), File.read("./spec/kern/assets/vm/config5.rb")
|
706
|
+
|
707
|
+
#vm_commit:0
|
708
|
+
#| Triangle | Circle | -> | Triangle | Square |
|
709
|
+
#| | Q | -> | Z | |
|
710
|
+
#newer older
|
711
|
+
reload_vm_commit_pages(ctx)
|
712
|
+
dump = ctx.evald %{
|
713
|
+
dump.newer = triangle_circle_null_q;
|
714
|
+
dump.older = triangle_square_z_null;
|
715
|
+
vm_commit(dump.older, dump.newer);
|
716
|
+
}
|
717
|
+
|
718
|
+
verify_vm_page_entries(dump["newer"], [
|
719
|
+
{"_id" => "id0", "value" => "Triangle"},
|
720
|
+
{"_id" => "id1", "value" => "Circle"},
|
721
|
+
{"_id" => "id3", "value" => "Q"},
|
722
|
+
])
|
723
|
+
|
724
|
+
#Changes match
|
725
|
+
verify_vm_diff(dump["newer"]["__changes"], [
|
726
|
+
{type: "M", args: [{"_id" => "id1", "value" => "Circle"}]},
|
727
|
+
{type: "-", args: ["id2"]},
|
728
|
+
{type: "+", args: [2, {"_id" => "id3", "value" => "Q"}]},
|
729
|
+
])
|
730
|
+
|
731
|
+
#No base but does include changes
|
732
|
+
expect(dump["newer"]["__changes_id"]).not_to eq(nil)
|
733
|
+
expect(dump["newer"]["__base"]).to eq(nil)
|
734
|
+
|
735
|
+
#vm_commit:1 older[nobase, changes]
|
736
|
+
#| Triangle | Circle | -> | Triangle | Square | --__changes-- | ----- |
|
737
|
+
#| | Q | -> | Z | | | |x| | Add (+) |
|
738
|
+
#newer older | ----- Triangle |
|
739
|
+
# | | | | |
|
740
|
+
# | ----- |
|
741
|
+
# | ----- |
|
742
|
+
# | | | | Modify (M) |
|
743
|
+
# | ----- Z |
|
744
|
+
# | |x| | |
|
745
|
+
# | ----- |
|
746
|
+
# | ----- |
|
747
|
+
# | | | | Remove (-) |
|
748
|
+
# | ----- |
|
749
|
+
# | | |x| |
|
750
|
+
# | ----- |
|
751
|
+
reload_vm_commit_pages(ctx)
|
752
|
+
dump = ctx.evald %{
|
753
|
+
dump.newer = triangle_circle_null_q;
|
754
|
+
dump.older = triangle_square_z_null;
|
755
|
+
dump.older.__changes_id = "XXXXX";
|
756
|
+
dump.older.__changes = [
|
757
|
+
["+", 0, {"_id": "id0", "_sig": "Triangle", "value": "Triangle"}],
|
758
|
+
["M", {"_id": "id2", "_sig": "Z", "value": "Z"}],
|
759
|
+
["-", "id3"],
|
760
|
+
|
761
|
+
]
|
762
|
+
vm_commit(dump.older, dump.newer);
|
763
|
+
}
|
764
|
+
|
765
|
+
verify_vm_page_entries(dump["newer"], [
|
766
|
+
{"_id" => "id0", "value" => "Triangle"},
|
767
|
+
{"_id" => "id1", "value" => "Circle"},
|
768
|
+
{"_id" => "id3", "value" => "Q"},
|
769
|
+
])
|
770
|
+
|
771
|
+
#Changes match
|
772
|
+
verify_vm_diff(dump["newer"]["__changes"], [
|
773
|
+
{type: "M", args: [{"_id" => "id1", "value" => "Circle"}]},
|
774
|
+
{type: "-", args: ["id2"]},
|
775
|
+
{type: "+", args: [2, {"_id" => "id3", "value" => "Q"}]},
|
776
|
+
])
|
777
|
+
expect(dump["newer"]["__changes_id"]).not_to eq(nil)
|
778
|
+
|
779
|
+
#Base with changes
|
780
|
+
verify_vm_page_entries(dump["newer"]["__base"], [
|
781
|
+
{"_id" => "id0", "value" => "Triangle"},
|
782
|
+
{"_id" => "id1", "value" => "Square"},
|
783
|
+
{"_id" => "id2", "value" => "Z"},
|
784
|
+
])
|
785
|
+
verify_vm_diff(dump["newer"]["__base"]["__changes"], [
|
786
|
+
{type: "+", args: [0, {"_id" => "id0", "value" => "Triangle"}]},
|
787
|
+
{type: "-", args: ["id3"]},
|
788
|
+
{type: "M", args: [{"_id" => "id2", "value" => "Z"}]},
|
789
|
+
])
|
790
|
+
expect(dump["newer"]["__base"]["__changes_id"]).not_to eq(nil)
|
791
|
+
expect(dump["newer"]["__base"]["__base"]).to eq(nil)
|
792
|
+
|
793
|
+
#vm_commit:2 older[base[nobase, changes], changes]
|
794
|
+
#| Q | | -> | Triangle | Circle | --__changes-- | ----- |
|
795
|
+
#| Circle | Square | -> | | Q | | | |x| Modify (M) |
|
796
|
+
#newer ----------------------- | ----- Circle |
|
797
|
+
# | __base | | | | | |
|
798
|
+
# ----------------------- | ----- |
|
799
|
+
# | Triangle | Square | | ----- |
|
800
|
+
# | Z | | --__changes- | | | | Remove (-) |
|
801
|
+
# older | | ----- |
|
802
|
+
# | | |x| | |
|
803
|
+
# | | ----- |
|
804
|
+
# | | ----- |
|
805
|
+
# | | | | | Insert (+) |
|
806
|
+
# | | ----- Q |
|
807
|
+
# | | | |x| |
|
808
|
+
# | | ----- |
|
809
|
+
# | --------------------
|
810
|
+
# |
|
811
|
+
# |- | ----- |
|
812
|
+
# | |x| | Add (+) |
|
813
|
+
# | ----- Triangle |
|
814
|
+
# | | | | |
|
815
|
+
# | ----- |
|
816
|
+
# | ----- |
|
817
|
+
# | | | | Modify (M) |
|
818
|
+
# | ----- Z |
|
819
|
+
# | |x| | |
|
820
|
+
# | ----- |
|
821
|
+
# | ----- |
|
822
|
+
# | | | | Remove (-) |
|
823
|
+
# | ----- |
|
824
|
+
# | | |x| |
|
825
|
+
# | ----- |
|
826
|
+
reload_vm_commit_pages(ctx)
|
827
|
+
dump = ctx.evald %{
|
828
|
+
dump.newer = q_null_circle_square;
|
829
|
+
dump.older = triangle_circle_null_q;
|
830
|
+
dump.older.__changes_id = "XXXXX";
|
831
|
+
dump.older.__changes = [
|
832
|
+
["M", {"_id": "id0", "_sig": "Circle", "value": "Circle"}],
|
833
|
+
["-", "id2"],
|
834
|
+
["+", 2, {"_id": "id3", "_sig": "Q", "value": "Q"}],
|
835
|
+
]
|
836
|
+
|
837
|
+
//Also, base on older
|
838
|
+
dump.older.__base = triangle_square_z_null;
|
839
|
+
dump.older.__base.__changes = [
|
840
|
+
["+", 0, {"_id": "id0", "_sig": "Triangle", "value": "Triangle"}],
|
841
|
+
["M", {"_id": "id2", "_sig": "Z", "value": "Z"}],
|
842
|
+
["-", "id3"],
|
843
|
+
]
|
844
|
+
dump.older.__base.__changes_id = "YYYYYYY";
|
845
|
+
vm_commit(dump.older, dump.newer);
|
846
|
+
}
|
847
|
+
|
848
|
+
verify_vm_page_entries(dump["newer"], [
|
849
|
+
{"_id" => "id0", "value" => "Q"},
|
850
|
+
{"_id" => "id2", "value" => "Circle"},
|
851
|
+
{"_id" => "id3", "value" => "Square"},
|
852
|
+
])
|
853
|
+
|
854
|
+
#Changes match
|
855
|
+
verify_vm_diff(dump["newer"]["__changes"], [
|
856
|
+
{type: "M", args: [{"_id" => "id0", "value" => "Q"}]},
|
857
|
+
{type: "-", args: ["id1"]},
|
858
|
+
{type: "M", args: [{"_id" => "id2", "value" => "Circle"}]},
|
859
|
+
{type: "+", args: [2, {"_id" => "id3", "value" => "Square"}]},
|
860
|
+
])
|
861
|
+
expect(dump["newer"]["__changes_id"]).not_to eq(nil)
|
862
|
+
|
863
|
+
#Base with changes
|
864
|
+
verify_vm_page_entries(dump["newer"]["__base"], [
|
865
|
+
{"_id" => "id0", "value" => "Triangle"},
|
866
|
+
{"_id" => "id1", "value" => "Square"},
|
867
|
+
{"_id" => "id2", "value" => "Z"},
|
868
|
+
])
|
869
|
+
verify_vm_diff(dump["newer"]["__base"]["__changes"], [
|
870
|
+
{type: "+", args: [0, {"_id" => "id0", "value" => "Triangle"}]},
|
871
|
+
{type: "M", args: [{"_id" => "id2", "value" => "Z"}]},
|
872
|
+
{type: "-", args: ["id3"]},
|
873
|
+
])
|
874
|
+
expect(dump["newer"]["__base"]["__changes_id"]).not_to eq(nil)
|
875
|
+
expect(dump["newer"]["__base"]["__base"]).to eq(nil)
|
876
|
+
end
|
877
|
+
|
878
|
+
it "can use vm_rebase" do
|
879
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller22.rb'), File.read("./spec/kern/assets/vm/config5.rb")
|
880
|
+
|
881
|
+
#vm_rebase:0 newer[nobase, nochange]
|
882
|
+
#| Triangle | Circle | -> | Triangle | Square |
|
883
|
+
#| | Q | -> | Z | |
|
884
|
+
#older newer
|
885
|
+
reload_vm_commit_pages(ctx)
|
886
|
+
dump = ctx.evald %{
|
887
|
+
dump.older = triangle_circle_null_q;
|
888
|
+
dump.newer = triangle_square_z_null;
|
889
|
+
vm_rebase(dump.newer, dump.older);
|
890
|
+
}
|
891
|
+
|
892
|
+
verify_vm_page_entries(dump["older"], [
|
893
|
+
{"_id" => "id0", "value" => "Triangle"},
|
894
|
+
{"_id" => "id1", "value" => "Circle"},
|
895
|
+
{"_id" => "id3", "value" => "Q"},
|
896
|
+
])
|
897
|
+
|
898
|
+
#No base & No changes
|
899
|
+
expect(dump["older"]["__changes"]).to eq(nil)
|
900
|
+
expect(dump["older"]["__changes_id"]).to eq(nil)
|
901
|
+
expect(dump["older"]["__base"]).to eq(nil)
|
902
|
+
|
903
|
+
#vm_rebase:1 newer[nobase, changes]
|
904
|
+
#| P | Circle | -> | Triangle | Square | --__changes-- | ----- |
|
905
|
+
#| | Q | -> | Z | | | | |x| Add (+) |
|
906
|
+
#older newer | ----- Square |
|
907
|
+
# | | | | |
|
908
|
+
# | ----- |
|
909
|
+
# | ----- |
|
910
|
+
# | | | | Modify (M) |
|
911
|
+
# | ----- Z |
|
912
|
+
# | |x| | |
|
913
|
+
# | ----- |
|
914
|
+
# | ----- |
|
915
|
+
# | | | | Remove (-) |
|
916
|
+
# | ----- |
|
917
|
+
# | | |x| |
|
918
|
+
# | ----- |
|
919
|
+
reload_vm_commit_pages(ctx)
|
920
|
+
dump = ctx.evald %{
|
921
|
+
dump.older = p_circle_null_q;
|
922
|
+
dump.newer = triangle_square_z_null;
|
923
|
+
dump.newer.__changes = [
|
924
|
+
["+", 0, {"_id": "id1", "_sig": "Square", "value": "Square"}],
|
925
|
+
["M", {"_id": "id2", "_sig": "Z", "value": "Z"}],
|
926
|
+
["-", "id3"],
|
927
|
+
]
|
928
|
+
dump.newer.__changes_id = "XXXXXXXXXXX";
|
929
|
+
vm_rebase(dump.newer, dump.older);
|
930
|
+
}
|
931
|
+
|
932
|
+
verify_vm_page_entries(dump["older"], [
|
933
|
+
{"_id" => "id0", "value" => "P"},
|
934
|
+
{"_id" => "id1", "value" => "Circle"},
|
935
|
+
])
|
936
|
+
|
937
|
+
#Changes match
|
938
|
+
verify_vm_diff(dump["older"]["__changes"], [
|
939
|
+
{type: "+", args: [0, {"_id" => "id1", "value" => "Square"}]},
|
940
|
+
{type: "M", args: [{"_id" => "id2", "value" => "Z"}]},
|
941
|
+
{type: "-", args: ["id3"]},
|
942
|
+
])
|
943
|
+
expect(dump["older"]["__changes_id"]).not_to eq(nil)
|
944
|
+
|
945
|
+
#No base
|
946
|
+
expect(dump["older"]["__base"]).to eq(nil)
|
947
|
+
|
948
|
+
#vm_rebase:2 newer[base[nobase, changes], changes]
|
949
|
+
#| P | Circle | -> | Triangle | Square | --__changes-- | ----- |
|
950
|
+
#| | Q | -> | K | | | | |x| Add (+) |
|
951
|
+
#older ----------------------- | ----- Square |
|
952
|
+
# | __base | | | | | |
|
953
|
+
# ----------------------- | ----- |
|
954
|
+
# | Triangle | | | ----- |
|
955
|
+
# | A | M | --__changes- | | | | Modify (M) |
|
956
|
+
# newer | | ----- Z |
|
957
|
+
# | | |x| | |
|
958
|
+
# | | ----- |
|
959
|
+
# | | ----- |
|
960
|
+
# | | | | | Remove (-) |
|
961
|
+
# | | ----- |
|
962
|
+
# | | | |x| |
|
963
|
+
# | | ----- |
|
964
|
+
# | --------------------
|
965
|
+
# |
|
966
|
+
# |- | ----- |
|
967
|
+
# | | |x| Remove (-) |
|
968
|
+
# | ----- |
|
969
|
+
# | | | | |
|
970
|
+
# | ----- |
|
971
|
+
# | ----- |
|
972
|
+
# | | | | Modify (M) |
|
973
|
+
# | ----- A |
|
974
|
+
# | |x| | |
|
975
|
+
# | ----- |
|
976
|
+
# | ----- |
|
977
|
+
# | | | | Add (+) |
|
978
|
+
# | ----- M |
|
979
|
+
# | | |x| |
|
980
|
+
# | ----- |
|
981
|
+
reload_vm_commit_pages(ctx)
|
982
|
+
dump = ctx.evald %{
|
983
|
+
dump.older = p_circle_null_q;
|
984
|
+
dump.newer = triangle_square_z_null;
|
985
|
+
dump.newer.__changes_id = "XXXXX";
|
986
|
+
dump.newer.__changes = [
|
987
|
+
["+", 0, {"_id": "id1", "_sig": "Square", "value": "Square"}],
|
988
|
+
["M", {"_id": "id2", "_sig": "Z", "value": "Z"}],
|
989
|
+
["-", "id3"],
|
990
|
+
]
|
991
|
+
|
992
|
+
//Also, base on older
|
993
|
+
dump.newer.__base = triangle_null_a_m;
|
994
|
+
dump.newer.__base.__changes = [
|
995
|
+
["-", "id1"],
|
996
|
+
["M", {"_id": "id2", "_sig": "A", "value": "A"}],
|
997
|
+
["+", 2, {"_id": "id3", "_sig": "+", "value": "M"}],
|
998
|
+
]
|
999
|
+
dump.newer.__base.__changes_id = "YYYYYYY";
|
1000
|
+
vm_rebase(dump.newer, dump.older);
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
verify_vm_page_entries(dump["older"], [
|
1004
|
+
{"_id" => "id0", "value" => "P"},
|
1005
|
+
{"_id" => "id1", "value" => "Square"},
|
1006
|
+
])
|
1007
|
+
|
1008
|
+
#Changes match
|
1009
|
+
verify_vm_diff(dump["older"]["__changes"], [
|
1010
|
+
{type: "+", args: [0, {"_id" => "id1", "value" => "Square"}]},
|
1011
|
+
{type: "-", args: ["id3"]},
|
1012
|
+
])
|
1013
|
+
expect(dump["older"]["__changes_id"]).not_to eq(nil)
|
1014
|
+
expect(dump["older"]["__changes_id"]).not_to eq("XXXXX")
|
1015
|
+
|
1016
|
+
#Base with changes
|
1017
|
+
verify_vm_page_entries(dump["older"]["__base"], [
|
1018
|
+
{"_id" => "id0", "value" => "P"},
|
1019
|
+
{"_id" => "id3", "value" => "Q"},
|
1020
|
+
])
|
1021
|
+
verify_vm_diff(dump["older"]["__base"]["__changes"], [
|
1022
|
+
{type: "-", args: ["id1"]},
|
1023
|
+
{type: "M", args: [{"_id" => "id2", "value" => "A"}]},
|
1024
|
+
{type: "+", args: [2, {"_id" => "id3", "value" => "M"}]},
|
1025
|
+
])
|
1026
|
+
expect(dump["older"]["__base"]["__changes_id"]).to eq("YYYYYYY")
|
1027
|
+
expect(dump["older"]["__base"]["__base"]).to eq(nil)
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
it "can use vm_mark_changes_synced" do
|
1031
|
+
ctx = flok_new_user File.read('./spec/kern/assets/vm/controller22.rb'), File.read("./spec/kern/assets/vm/config5.rb")
|
1032
|
+
|
1033
|
+
#Case A
|
1034
|
+
#Page with no changes. (Nothing happends)
|
1035
|
+
dump = ctx.evald %{
|
1036
|
+
dump.page = vm_create_page();
|
1037
|
+
vm_mark_changes_synced(dump.page, "changes_id");
|
1038
|
+
|
1039
|
+
dump.__changes_id_is_undefined = (dump.page.__changes_id === undefined)
|
1040
|
+
dump.__changes_is_undefined = (dump.page.__changes === undefined)
|
1041
|
+
}
|
1042
|
+
expect(dump["__changes_id_is_undefined"]).to eq(true)
|
1043
|
+
expect(dump["__changes_is_undefined"]).to eq(true)
|
1044
|
+
|
1045
|
+
#Case B
|
1046
|
+
#Page with changes, but changes_id given to vm_mark_changes_synced does not match (Nothing happends).
|
1047
|
+
dump = ctx.evald %{
|
1048
|
+
dump.page = vm_create_page();
|
1049
|
+
dump.page.__changes_id = "foo";
|
1050
|
+
dump.page.__changes = ["A"]
|
1051
|
+
vm_mark_changes_synced(dump.page, "bar");
|
1052
|
+
}
|
1053
|
+
expect(dump["page"]["__changes"]).to eq(["A"])
|
1054
|
+
expect(dump["page"]["__changes_id"]).to eq("foo")
|
1055
|
+
|
1056
|
+
#Case C
|
1057
|
+
#Page with changes but no base, and changes_id given to vm_mark_changes_synced does match __changes_id of page.
|
1058
|
+
#The __changes and __changes_id of the page will be removed.
|
1059
|
+
dump = ctx.evald %{
|
1060
|
+
dump.page = vm_create_page();
|
1061
|
+
dump.page.__changes_id = "foo";
|
1062
|
+
dump.page.__changes = ["A"]
|
1063
|
+
vm_mark_changes_synced(dump.page, "foo");
|
1064
|
+
|
1065
|
+
dump.__changes_id_is_undefined = (dump.page.__changes_id === undefined)
|
1066
|
+
dump.__changes_is_undefined = (dump.page.__changes === undefined)
|
1067
|
+
}
|
1068
|
+
expect(dump["__changes_id_is_undefined"]).to eq(true)
|
1069
|
+
expect(dump["__changes_is_undefined"]).to eq(true)
|
1070
|
+
|
1071
|
+
#Case D
|
1072
|
+
#Page with changes and a base[changes, nobase], and changes_id given to vm_mark_changes_synced does not match __base.__changes_id of page.
|
1073
|
+
#Nothing happends
|
1074
|
+
dump = ctx.evald %{
|
1075
|
+
dump.page = vm_create_page();
|
1076
|
+
dump.page.__changes_id = "foo";
|
1077
|
+
dump.page.__changes = ["A"]
|
1078
|
+
|
1079
|
+
//Attach base [unbased, changes]
|
1080
|
+
dump.page.__base = vm_create_page();
|
1081
|
+
dump.page.__base.__changes_id = "bar";
|
1082
|
+
dump.page.__base.__changes = ["B"]
|
1083
|
+
|
1084
|
+
vm_mark_changes_synced(dump.page, "foo");
|
1085
|
+
}
|
1086
|
+
expect(dump["page"]["__changes"]).to eq(["A"])
|
1087
|
+
expect(dump["page"]["__changes_id"]).to eq("foo")
|
1088
|
+
|
1089
|
+
#Case E
|
1090
|
+
#Page with changes and a base[changes, nobase], and changes_id given to vm_mark_changes_synced does match __base.__changes_id of page.
|
1091
|
+
#The base will be removed, but the page's __changes and __changes_id will remain.
|
1092
|
+
dump = ctx.evald %{
|
1093
|
+
dump.page = vm_create_page();
|
1094
|
+
dump.page.__changes_id = "foo";
|
1095
|
+
dump.page.__changes = ["A"]
|
1096
|
+
|
1097
|
+
//Attach base [unbased, changes]
|
1098
|
+
dump.page.__base = vm_create_page();
|
1099
|
+
dump.page.__base.__changes_id = "bar";
|
1100
|
+
dump.page.__base.__changes = ["B"]
|
1101
|
+
|
1102
|
+
vm_mark_changes_synced(dump.page, "bar");
|
1103
|
+
|
1104
|
+
dump.__base_is_undefined = (dump.page.__base === undefined)
|
1105
|
+
}
|
1106
|
+
expect(dump["__base_is_undefined"]).to eq(true)
|
1107
|
+
expect(dump["page"]["__changes"]).to eq(["A"])
|
1108
|
+
expect(dump["page"]["__changes_id"]).to eq("foo")
|
1109
|
+
end
|
1110
|
+
###########################################################################
|
1111
|
+
end
|