factbase 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +5 -5
- data/factbase.gemspec +4 -4
- data/lib/factbase/fact.rb +1 -1
- data/lib/factbase/fact_as_yaml.rb +10 -1
- data/lib/factbase/indexed/indexed_term.rb +6 -1
- data/lib/factbase/version.rb +1 -1
- metadata +7 -87
- data/.0pdd.yml +0 -8
- data/.gitattributes +0 -7
- data/.github/publish-benchmark.sh +0 -24
- data/.github/workflows/actionlint.yml +0 -25
- data/.github/workflows/benchmark.yml +0 -36
- data/.github/workflows/codecov.yml +0 -27
- data/.github/workflows/copyrights.yml +0 -19
- data/.github/workflows/markdown-lint.yml +0 -23
- data/.github/workflows/pdd.yml +0 -19
- data/.github/workflows/rake.yml +0 -28
- data/.github/workflows/reuse.yml +0 -19
- data/.github/workflows/typos.yml +0 -19
- data/.github/workflows/xcop.yml +0 -19
- data/.github/workflows/yamllint.yml +0 -19
- data/.gitignore +0 -11
- data/.pdd +0 -7
- data/.rubocop.yml +0 -51
- data/.rultor.yml +0 -27
- data/benchmark/bench_factbase.rb +0 -61
- data/benchmark/bench_large_query.rb +0 -128
- data/benchmark/bench_query.rb +0 -57
- data/benchmark/bench_taped.rb +0 -33
- data/fixtures/stories/agg.yml +0 -17
- data/fixtures/stories/always.yml +0 -16
- data/fixtures/stories/and.yml +0 -19
- data/fixtures/stories/as.yml +0 -16
- data/fixtures/stories/count.yml +0 -18
- data/fixtures/stories/empty.yml +0 -23
- data/fixtures/stories/eq.yml +0 -30
- data/fixtures/stories/gt.yml +0 -18
- data/fixtures/stories/join.yml +0 -22
- data/fixtures/stories/max.yml +0 -14
- data/fixtures/stories/min.yml +0 -14
- data/fixtures/stories/nth.yml +0 -14
- data/fixtures/stories/one.yml +0 -14
- data/fixtures/stories/or.yml +0 -18
- data/fixtures/stories/sprintf.yml +0 -12
- data/fixtures/stories/sum.yml +0 -14
- data/fixtures/stories/unique.yml +0 -30
- data/renovate.json +0 -6
- data/test/factbase/cached/test_cached_factbase.rb +0 -44
- data/test/factbase/cached/test_cached_query.rb +0 -100
- data/test/factbase/indexed/test_indexed_fact.rb +0 -23
- data/test/factbase/indexed/test_indexed_factbase.rb +0 -96
- data/test/factbase/indexed/test_indexed_query.rb +0 -208
- data/test/factbase/indexed/test_indexed_term.rb +0 -140
- data/test/factbase/sync/test_sync_factbase.rb +0 -22
- data/test/factbase/sync/test_sync_query.rb +0 -30
- data/test/factbase/terms/test_aggregates.rb +0 -63
- data/test/factbase/terms/test_aliases.rb +0 -58
- data/test/factbase/terms/test_casting.rb +0 -33
- data/test/factbase/terms/test_debug.rb +0 -111
- data/test/factbase/terms/test_defn.rb +0 -48
- data/test/factbase/terms/test_logical.rb +0 -57
- data/test/factbase/terms/test_math.rb +0 -122
- data/test/factbase/terms/test_meta.rb +0 -70
- data/test/factbase/terms/test_ordering.rb +0 -44
- data/test/factbase/terms/test_strings.rb +0 -36
- data/test/factbase/terms/test_system.rb +0 -31
- data/test/factbase/test_accum.rb +0 -74
- data/test/factbase/test_churn.rb +0 -41
- data/test/factbase/test_fact.rb +0 -108
- data/test/factbase/test_fact_as_yaml.rb +0 -77
- data/test/factbase/test_flatten.rb +0 -28
- data/test/factbase/test_impatient.rb +0 -176
- data/test/factbase/test_inv.rb +0 -44
- data/test/factbase/test_logged.rb +0 -155
- data/test/factbase/test_pre.rb +0 -35
- data/test/factbase/test_query.rb +0 -445
- data/test/factbase/test_rules.rb +0 -128
- data/test/factbase/test_syntax.rb +0 -166
- data/test/factbase/test_tallied.rb +0 -81
- data/test/factbase/test_taped.rb +0 -72
- data/test/factbase/test_tee.rb +0 -85
- data/test/factbase/test_term.rb +0 -87
- data/test/factbase/test_to_json.rb +0 -35
- data/test/factbase/test_to_xml.rb +0 -89
- data/test/factbase/test_to_yaml.rb +0 -39
- data/test/test__helper.rb +0 -41
- data/test/test_factbase.rb +0 -509
@@ -1,166 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../test__helper'
|
7
|
-
require_relative '../../lib/factbase/syntax'
|
8
|
-
|
9
|
-
# Syntax test.
|
10
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
11
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
12
|
-
# License:: MIT
|
13
|
-
class TestSyntax < Factbase::Test
|
14
|
-
def test_parses_string_right
|
15
|
-
[
|
16
|
-
"(foo 'abc')",
|
17
|
-
"(foo 'one two')",
|
18
|
-
"(foo 'one two three ')",
|
19
|
-
"(foo 'one two three ' 'tail tail')"
|
20
|
-
].each do |q|
|
21
|
-
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s, q)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_makes_abstract_terms
|
26
|
-
{
|
27
|
-
'(foo $bar)' => true,
|
28
|
-
'(foo (bar (a (b c (f $bar)))))' => true,
|
29
|
-
'(foo (bar (a (b c (f bar)))))' => false
|
30
|
-
}.each do |q, a|
|
31
|
-
assert_equal(a, Factbase::Syntax.new(q).to_term.abstract?)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_makes_static_terms
|
36
|
-
{
|
37
|
-
'(foo bar)' => false,
|
38
|
-
'(foo "bar")' => true,
|
39
|
-
'(agg (always) (max id))' => true
|
40
|
-
}.each do |q, a|
|
41
|
-
assert_equal(a, Factbase::Syntax.new(q).to_term.static?)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def test_simple_parsing
|
46
|
-
[
|
47
|
-
'(foo)',
|
48
|
-
'(foo (bar) (zz 77) ) # hey',
|
49
|
-
"# hello\n\n\n(foo ($bar))",
|
50
|
-
"(eq foo \n\n 'Hello, world!'\n)\n",
|
51
|
-
"(eq x 'Hello, \\' \n) \\' ( world!')",
|
52
|
-
"# this is a comment\n(eq foo # test\n 42)\n\n# another comment\n",
|
53
|
-
"(foo 'Hello,\n\nworld!\r\t\n')\n",
|
54
|
-
"(or ( a 4) (b 5) (always) (and (always) (c 5) \t\t(r 7 w8s w8is 'Foo')))"
|
55
|
-
].each do |q|
|
56
|
-
refute_nil(Factbase::Syntax.new(q).to_term)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def test_exact_parsing
|
61
|
-
[
|
62
|
-
'(foo)',
|
63
|
-
'(foo 7)',
|
64
|
-
"(foo 7 'Dude')",
|
65
|
-
"(r 'Dude\\'s Friend')",
|
66
|
-
"(r 'I\\'m \\\"good\\\"')",
|
67
|
-
'(foo x y z)',
|
68
|
-
"(foo x y z t f 42 'Hi!# you' 33)",
|
69
|
-
'(foo (x) y z)',
|
70
|
-
'(eq t 2024-05-25T19:43:48Z)',
|
71
|
-
'(eq t 2024-05-25T19:43:48Z)',
|
72
|
-
'(eq t 3.1415926)',
|
73
|
-
'(eq t 3.0e+21)',
|
74
|
-
"(foo (x (f (t (y 42 'Hey you'))) (never) (r 3)) y z)"
|
75
|
-
].each do |q|
|
76
|
-
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s, q)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_simple_matching
|
81
|
-
m = {
|
82
|
-
'foo' => ['Hello, world!'],
|
83
|
-
'bar' => [42],
|
84
|
-
'z' => [1, 2, 3, 4]
|
85
|
-
}
|
86
|
-
{
|
87
|
-
'(eq z 1)' => true,
|
88
|
-
'(or (eq bar 888) (eq z 1))' => true,
|
89
|
-
"(or (gt bar 100) (eq foo 'Hello, world!'))" => true
|
90
|
-
}.each do |k, v|
|
91
|
-
assert_equal(v, Factbase::Syntax.new(k).to_term.evaluate(m, [], Factbase.new), k)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def test_broken_syntax
|
96
|
-
[
|
97
|
-
'',
|
98
|
-
'()',
|
99
|
-
'(foo',
|
100
|
-
'(foo $)',
|
101
|
-
'(foo 1) (bar 2)',
|
102
|
-
'some text',
|
103
|
-
'"hello, world!',
|
104
|
-
'(foo 7',
|
105
|
-
"(foo 7 'Dude'",
|
106
|
-
'(foo x y z (',
|
107
|
-
'(bad-term-name 42)',
|
108
|
-
'(foo x y (z t (f 42 ',
|
109
|
-
')foo ) y z)',
|
110
|
-
'(x "")',
|
111
|
-
")y 42 'Hey you)",
|
112
|
-
')',
|
113
|
-
'"'
|
114
|
-
].each do |q|
|
115
|
-
msg = assert_raises(q) do
|
116
|
-
Factbase::Syntax.new(q).to_term
|
117
|
-
end.message
|
118
|
-
assert_includes(msg, q, msg)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def test_raises_on_broken_syntax
|
123
|
-
100.times do
|
124
|
-
q = [
|
125
|
-
'(', ')', '#test', '$foo', '%what',
|
126
|
-
'"hello"', '42', '+', '?', '!', '\"',
|
127
|
-
'\'', 'привет'
|
128
|
-
].shuffle.join(' . ')
|
129
|
-
assert_raises(Factbase::Syntax::Broken, q) do
|
130
|
-
Factbase::Syntax.new(q).to_term
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def test_simplification
|
136
|
-
{
|
137
|
-
'(foo)' => '(foo)',
|
138
|
-
'(and (foo) (foo))' => '(foo)',
|
139
|
-
'(and (foo) (or (and (eq a 1))) (eq a 1) (foo))' => '(and (foo) (eq a 1))'
|
140
|
-
}.each do |s, t|
|
141
|
-
assert_equal(t, Factbase::Syntax.new(s).to_term.to_s)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def test_fails_when_term_is_not_a_class
|
146
|
-
assert_raises(StandardError) { Factbase::Syntax.new('(foo 1)', term: 'hello') }
|
147
|
-
end
|
148
|
-
|
149
|
-
def test_fails_when_term_is_wrong_class
|
150
|
-
assert_raises(StandardError) { Factbase::Syntax.new('(bar 1)', term: String).to_term }
|
151
|
-
end
|
152
|
-
|
153
|
-
def test_fails_when_term_is_incorrectly_defined_class
|
154
|
-
assert_includes(
|
155
|
-
assert_raises(StandardError) { Factbase::Syntax.new('(bar 1)', term: FakeTerm).to_term }.message,
|
156
|
-
'wrong number of arguments'
|
157
|
-
)
|
158
|
-
end
|
159
|
-
|
160
|
-
class FakeTerm < Factbase::Term
|
161
|
-
def initialize(invalid)
|
162
|
-
super
|
163
|
-
@x = invalid
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../test__helper'
|
7
|
-
require 'threads'
|
8
|
-
require_relative '../../lib/factbase'
|
9
|
-
require_relative '../../lib/factbase/tallied'
|
10
|
-
|
11
|
-
# Test.
|
12
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
13
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
14
|
-
# License:: MIT
|
15
|
-
class TestTallied < Factbase::Test
|
16
|
-
def test_counts_size
|
17
|
-
fb = Factbase::Tallied.new(Factbase.new)
|
18
|
-
assert_equal(0, fb.size)
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_queries_empty_factbase
|
22
|
-
fb = Factbase::Tallied.new(Factbase.new)
|
23
|
-
assert_equal(0, fb.query('(gt foo 1)').each.to_a.size)
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_counts_simple_changes
|
27
|
-
fb = Factbase::Tallied.new(Factbase.new)
|
28
|
-
fb.insert.bar = 3
|
29
|
-
fb.query('(exists bar)').each do |f|
|
30
|
-
f.foo = 42
|
31
|
-
end
|
32
|
-
assert_equal(1, fb.churn.inserted)
|
33
|
-
assert_equal(0, fb.churn.deleted)
|
34
|
-
assert_equal(2, fb.churn.added)
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_counts_in_one
|
38
|
-
fb = Factbase::Tallied.new(Factbase.new)
|
39
|
-
fb.insert.bar = 3
|
40
|
-
assert_equal(1, fb.query('(agg (eq bar 3) (count))').one)
|
41
|
-
assert_equal(1, fb.churn.added)
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_returns_all_props
|
45
|
-
fb = Factbase::Tallied.new(Factbase.new)
|
46
|
-
f = fb.insert
|
47
|
-
f.bar = 3
|
48
|
-
assert_includes(f.all_properties, 'bar')
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_counts_in_txn
|
52
|
-
fb = Factbase::Tallied.new(Factbase.new)
|
53
|
-
fb.txn do |fbt|
|
54
|
-
fbt.insert.boom = 3
|
55
|
-
fbt.query('(exists boom)').each do |f|
|
56
|
-
f.foo = 88
|
57
|
-
end
|
58
|
-
end
|
59
|
-
assert_equal(1, fb.churn.inserted)
|
60
|
-
assert_equal(0, fb.churn.deleted)
|
61
|
-
assert_equal(2, fb.churn.added)
|
62
|
-
end
|
63
|
-
|
64
|
-
def test_counts_in_txn_in_threads
|
65
|
-
fb = Factbase::Tallied.new(Factbase.new)
|
66
|
-
t = 5
|
67
|
-
Threads.new(t).assert do |i|
|
68
|
-
fb.txn do |fbt|
|
69
|
-
fbt.insert.x = i
|
70
|
-
fbt.query("(eq x #{i})").each do |f|
|
71
|
-
f.send(:"a#{i}=", i)
|
72
|
-
end
|
73
|
-
fbt.query("(lt x #{t + 1})").delete!
|
74
|
-
end
|
75
|
-
end
|
76
|
-
assert_equal(0, fb.size)
|
77
|
-
assert_equal(t, fb.churn.inserted)
|
78
|
-
assert_equal(t, fb.churn.deleted)
|
79
|
-
assert_equal(t * 2, fb.churn.added)
|
80
|
-
end
|
81
|
-
end
|
data/test/factbase/test_taped.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../test__helper'
|
7
|
-
require_relative '../../lib/factbase'
|
8
|
-
require_relative '../../lib/factbase/taped'
|
9
|
-
|
10
|
-
# Test.
|
11
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
12
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
13
|
-
# License:: MIT
|
14
|
-
class TestTaped < Factbase::Test
|
15
|
-
def test_tracks_insertion
|
16
|
-
t = Factbase::Taped.new([])
|
17
|
-
t << {}
|
18
|
-
assert_equal(1, t.inserted.size)
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_joins_with_empty
|
22
|
-
t = Factbase::Taped.new([{ foo: 'yes' }])
|
23
|
-
t &= []
|
24
|
-
assert_equal(0, t.size)
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_disjoins_with_empty
|
28
|
-
t = Factbase::Taped.new([{ bar: 'oops' }])
|
29
|
-
t |= []
|
30
|
-
assert_equal(1, t.size)
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_tracks_deletion
|
34
|
-
t = Factbase::Taped.new([{ x: 1 }, { x: 2 }])
|
35
|
-
t.delete_if { |m| m[:x] == 1 }
|
36
|
-
assert_equal(1, t.deleted.size)
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_tracks_addition
|
40
|
-
h = { f: 5 }
|
41
|
-
t = Factbase::Taped.new([h])
|
42
|
-
t.each do |m|
|
43
|
-
m[:bar] = 66
|
44
|
-
end
|
45
|
-
assert_equal(1, t.added.size)
|
46
|
-
assert_equal(h.object_id, t.added.first)
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_tracks_addition_uniquely
|
50
|
-
h = { f: 5 }
|
51
|
-
t = Factbase::Taped.new([h])
|
52
|
-
t.each do |m|
|
53
|
-
m[:bar] = 66
|
54
|
-
m[:foo] = 77
|
55
|
-
end
|
56
|
-
assert_equal(1, t.added.size)
|
57
|
-
end
|
58
|
-
|
59
|
-
def test_tracks_factbase
|
60
|
-
t = Factbase::Taped.new([])
|
61
|
-
fb = Factbase.new(t)
|
62
|
-
fb.insert
|
63
|
-
fb.query('(always)').each do |f|
|
64
|
-
f.foo = 42
|
65
|
-
f.foo = 5
|
66
|
-
end
|
67
|
-
fb.query('(always)').delete!
|
68
|
-
assert_equal(1, t.inserted.size)
|
69
|
-
assert_equal(1, t.added.size)
|
70
|
-
assert_equal(1, t.deleted.size)
|
71
|
-
end
|
72
|
-
end
|
data/test/factbase/test_tee.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../test__helper'
|
7
|
-
require_relative '../../lib/factbase'
|
8
|
-
require_relative '../../lib/factbase/accum'
|
9
|
-
require_relative '../../lib/factbase/tee'
|
10
|
-
require_relative '../../lib/factbase/fact'
|
11
|
-
|
12
|
-
def global_function_for_test_only(foo)
|
13
|
-
raise foo
|
14
|
-
end
|
15
|
-
|
16
|
-
# Tee test.
|
17
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
18
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
19
|
-
# License:: MIT
|
20
|
-
class TestTee < Factbase::Test
|
21
|
-
def test_two_facts
|
22
|
-
prim = Factbase::Fact.new({})
|
23
|
-
prim.foo = 42
|
24
|
-
upper = Factbase::Fact.new({})
|
25
|
-
upper.bar = 13
|
26
|
-
t = Factbase::Tee.new(prim, upper)
|
27
|
-
assert_equal(42, t.foo)
|
28
|
-
assert_equal([13], t['$bar'])
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_no_trip_to_prim_if_not_found
|
32
|
-
prim = Factbase::Fact.new({})
|
33
|
-
prim.foo = 777
|
34
|
-
t = Factbase::Tee.new(prim, Factbase::Fact.new({}))
|
35
|
-
assert_nil(t['$foo'])
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_fetches_simply
|
39
|
-
t = Factbase::Accum.new(
|
40
|
-
Factbase::Tee.new(
|
41
|
-
Factbase::Fact.new({ 'foo_bar' => [987] }),
|
42
|
-
Factbase::Fact.new({})
|
43
|
-
),
|
44
|
-
{}, true
|
45
|
-
)
|
46
|
-
assert_equal(987, t.foo_bar)
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_fetches_without_conflict_with_global_name
|
50
|
-
t = Factbase::Tee.new(
|
51
|
-
Factbase::Fact.new({ 'global_function_for_test_only' => [2] }),
|
52
|
-
Factbase::Fact.new({})
|
53
|
-
)
|
54
|
-
assert_equal(2, t.global_function_for_test_only)
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_all_properties
|
58
|
-
prim = Factbase::Fact.new({})
|
59
|
-
prim.foo = 42
|
60
|
-
upper = Factbase::Fact.new({})
|
61
|
-
upper.bar = 13
|
62
|
-
t = Factbase::Tee.new(prim, upper)
|
63
|
-
assert_includes(t.all_properties, 'foo')
|
64
|
-
assert_includes(t.all_properties, 'bar')
|
65
|
-
end
|
66
|
-
|
67
|
-
def test_recursively
|
68
|
-
map = {}
|
69
|
-
prim = Factbase::Fact.new(map)
|
70
|
-
prim.foo = 42
|
71
|
-
t = Factbase::Tee.new(Factbase::Fact.new({}), { 'bar' => [7] })
|
72
|
-
assert_equal([7], t['$bar'])
|
73
|
-
t = Factbase::Tee.new(prim, t)
|
74
|
-
assert_equal([7], t['$bar'])
|
75
|
-
end
|
76
|
-
|
77
|
-
def test_prints_to_string
|
78
|
-
prim = Factbase::Fact.new({})
|
79
|
-
prim.foo = 42
|
80
|
-
upper = Factbase::Fact.new({})
|
81
|
-
upper.bar = 13
|
82
|
-
t = Factbase::Tee.new(prim, upper)
|
83
|
-
assert_equal('[ foo: [42] ]', t.to_s)
|
84
|
-
end
|
85
|
-
end
|
data/test/factbase/test_term.rb
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../test__helper'
|
7
|
-
require_relative '../../lib/factbase'
|
8
|
-
require_relative '../../lib/factbase/term'
|
9
|
-
|
10
|
-
# Term test.
|
11
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
12
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
13
|
-
# License:: MIT
|
14
|
-
class TestTerm < Factbase::Test
|
15
|
-
def test_false_matching
|
16
|
-
t = Factbase::Term.new(:never, [])
|
17
|
-
refute(t.evaluate(fact('foo' => [100]), [], Factbase.new))
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_size_matching
|
21
|
-
t = Factbase::Term.new(:size, [:foo])
|
22
|
-
assert_equal(3, t.evaluate(fact('foo' => [42, 12, -90]), [], Factbase.new))
|
23
|
-
assert_equal(0, t.evaluate(fact('bar' => 100), [], Factbase.new))
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_exists_matching
|
27
|
-
t = Factbase::Term.new(:exists, [:foo])
|
28
|
-
assert(t.evaluate(fact('foo' => [42, 12, -90]), [], Factbase.new))
|
29
|
-
refute(t.evaluate(fact('bar' => 100), [], Factbase.new))
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_absent_matching
|
33
|
-
t = Factbase::Term.new(:absent, [:foo])
|
34
|
-
assert(t.evaluate(fact('z' => [42, 12, -90]), [], Factbase.new))
|
35
|
-
refute(t.evaluate(fact('foo' => 100), [], Factbase.new))
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_type_matching
|
39
|
-
t = Factbase::Term.new(:type, [:foo])
|
40
|
-
assert_equal('Integer', t.evaluate(fact('foo' => 42), [], Factbase.new))
|
41
|
-
assert_equal('Integer', t.evaluate(fact('foo' => [42]), [], Factbase.new))
|
42
|
-
assert_equal('Array', t.evaluate(fact('foo' => [1, 2, 3]), [], Factbase.new))
|
43
|
-
assert_equal('String', t.evaluate(fact('foo' => 'Hello, world!'), [], Factbase.new))
|
44
|
-
assert_equal('Float', t.evaluate(fact('foo' => 3.14), [], Factbase.new))
|
45
|
-
assert_equal('Time', t.evaluate(fact('foo' => Time.now), [], Factbase.new))
|
46
|
-
assert_equal('Integer', t.evaluate(fact('foo' => 1_000_000_000_000_000), [], Factbase.new))
|
47
|
-
assert_equal('nil', t.evaluate(fact, [], Factbase.new))
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_past
|
51
|
-
t = Factbase::Term.new(:prev, [:foo])
|
52
|
-
assert_nil(t.evaluate(fact('foo' => 4), [], Factbase.new))
|
53
|
-
assert_equal([4], t.evaluate(fact('foo' => 5), [], Factbase.new))
|
54
|
-
end
|
55
|
-
|
56
|
-
def test_at
|
57
|
-
t = Factbase::Term.new(:at, [1, :foo])
|
58
|
-
assert_nil(t.evaluate(fact('foo' => 4), [], Factbase.new))
|
59
|
-
assert_equal(5, t.evaluate(fact('foo' => [4, 5]), [], Factbase.new))
|
60
|
-
end
|
61
|
-
|
62
|
-
def test_report_missing_term
|
63
|
-
t = Factbase::Term.new(:something, [])
|
64
|
-
msg = assert_raises(StandardError) do
|
65
|
-
t.evaluate(fact, [], Factbase.new)
|
66
|
-
end.message
|
67
|
-
assert_includes(msg, 'not defined at (something)', msg)
|
68
|
-
end
|
69
|
-
|
70
|
-
def test_report_other_error
|
71
|
-
t = Factbase::Term.new(:at, [])
|
72
|
-
msg = assert_raises(StandardError) do
|
73
|
-
t.evaluate(fact, [], Factbase.new)
|
74
|
-
end.message
|
75
|
-
assert_includes(msg, 'at (at)', msg)
|
76
|
-
end
|
77
|
-
|
78
|
-
def test_redresses_itself
|
79
|
-
t = Factbase::Term.new(:something, [])
|
80
|
-
require_relative '../../lib/factbase/indexed/indexed_term'
|
81
|
-
t.redress!(Factbase::IndexedTerm)
|
82
|
-
require_relative '../../lib/factbase/cached/cached_term'
|
83
|
-
t.redress!(Factbase::CachedTerm)
|
84
|
-
assert_kind_of(Factbase::CachedTerm, t)
|
85
|
-
refute_kind_of(Factbase::CachedTerm, Factbase::Term.new(:something, []))
|
86
|
-
end
|
87
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../test__helper'
|
7
|
-
require 'loog'
|
8
|
-
require_relative '../../lib/factbase'
|
9
|
-
require_relative '../../lib/factbase/to_json'
|
10
|
-
|
11
|
-
# Test.
|
12
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
13
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
14
|
-
# License:: MIT
|
15
|
-
class TestToJSON < Factbase::Test
|
16
|
-
def test_simple_rendering
|
17
|
-
fb = Factbase.new
|
18
|
-
f = fb.insert
|
19
|
-
f.foo = 42
|
20
|
-
f.foo = 256
|
21
|
-
to = Factbase::ToJSON.new(fb)
|
22
|
-
json = JSON.parse(to.json)
|
23
|
-
assert_equal(256, json[0]['foo'][1])
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_sort_keys
|
27
|
-
fb = Factbase.new
|
28
|
-
f = fb.insert
|
29
|
-
f.c = 42
|
30
|
-
f.b = 1
|
31
|
-
f.a = 256
|
32
|
-
json = Factbase::ToJSON.new(fb).json
|
33
|
-
assert_includes(json, '{"a":256,"b":1,"c":42}', json)
|
34
|
-
end
|
35
|
-
end
|
@@ -1,89 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../test__helper'
|
7
|
-
require 'loog'
|
8
|
-
require_relative '../../lib/factbase'
|
9
|
-
require_relative '../../lib/factbase/to_xml'
|
10
|
-
|
11
|
-
# Test.
|
12
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
13
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
14
|
-
# License:: MIT
|
15
|
-
class TestToXML < Factbase::Test
|
16
|
-
def test_simple_rendering
|
17
|
-
fb = Factbase.new
|
18
|
-
fb.insert.t = Time.now
|
19
|
-
to = Factbase::ToXML.new(fb)
|
20
|
-
xml = Nokogiri::XML.parse(to.xml)
|
21
|
-
refute_empty(xml.xpath('/fb/f[t]'))
|
22
|
-
assert_match(
|
23
|
-
/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$/, xml.xpath('/fb/f/t/text()').text
|
24
|
-
)
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_complex_rendering
|
28
|
-
fb = Factbase.new
|
29
|
-
fb.insert.t = "\uffff < > & ' \""
|
30
|
-
to = Factbase::ToXML.new(fb)
|
31
|
-
xml = Nokogiri::XML.parse(to.xml)
|
32
|
-
refute_empty(xml.xpath('/fb/f[t]'))
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_meta_data_presence
|
36
|
-
fb = Factbase.new
|
37
|
-
fb.insert.x = 42
|
38
|
-
to = Factbase::ToXML.new(fb)
|
39
|
-
xml = Nokogiri::XML.parse(to.xml)
|
40
|
-
refute_empty(xml.xpath('/fb[@version]'))
|
41
|
-
refute_empty(xml.xpath('/fb[@size]'))
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_to_xml_with_short_names
|
45
|
-
fb = Factbase.new
|
46
|
-
f = fb.insert
|
47
|
-
f.type = 1
|
48
|
-
f.f = 2
|
49
|
-
to = Factbase::ToXML.new(fb)
|
50
|
-
xml = Nokogiri::XML.parse(to.xml)
|
51
|
-
refute_empty(xml.xpath('/fb/f/type'))
|
52
|
-
refute_empty(xml.xpath('/fb/f/f'))
|
53
|
-
end
|
54
|
-
|
55
|
-
def test_show_types_as_attributes
|
56
|
-
fb = Factbase.new
|
57
|
-
f = fb.insert
|
58
|
-
f.a = 42
|
59
|
-
f.b = 3.14
|
60
|
-
f.c = 'Hello'
|
61
|
-
f.d = Time.now
|
62
|
-
f.e = 'e'
|
63
|
-
f.e = 4
|
64
|
-
out = Factbase::ToXML.new(fb).xml
|
65
|
-
xml = Nokogiri::XML.parse(out)
|
66
|
-
[
|
67
|
-
'/fb/f/a[@t="I"]',
|
68
|
-
'/fb/f/b[@t="F"]',
|
69
|
-
'/fb/f/c[@t="S"]',
|
70
|
-
'/fb/f/d[@t="T"]',
|
71
|
-
'/fb/f/e/v[@t="S"]',
|
72
|
-
'/fb/f/e/v[@t="I"]'
|
73
|
-
].each { |x| refute_empty(xml.xpath(x), out) }
|
74
|
-
end
|
75
|
-
|
76
|
-
def test_sorts_keys
|
77
|
-
fb = Factbase.new
|
78
|
-
f = fb.insert
|
79
|
-
f.x = 20
|
80
|
-
f.t = 40
|
81
|
-
f.a = 10
|
82
|
-
f.c = 1
|
83
|
-
to = Factbase::ToXML.new(fb)
|
84
|
-
xml = Nokogiri::XML.parse(to.xml)
|
85
|
-
%w[a c t x].each_with_index do |e, i|
|
86
|
-
refute_empty(xml.xpath("/fb/f/#{e}[count(preceding-sibling::*) = #{i}]"), e)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../test__helper'
|
7
|
-
require 'loog'
|
8
|
-
require_relative '../../lib/factbase'
|
9
|
-
require_relative '../../lib/factbase/to_yaml'
|
10
|
-
|
11
|
-
# Test.
|
12
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
13
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
14
|
-
# License:: MIT
|
15
|
-
class TestToYAML < Factbase::Test
|
16
|
-
def test_simple_rendering
|
17
|
-
fb = Factbase.new
|
18
|
-
f = fb.insert
|
19
|
-
f._id = 1
|
20
|
-
f.foo = 42
|
21
|
-
f.foo = 256
|
22
|
-
fb.insert._id = 2
|
23
|
-
to = Factbase::ToYAML.new(fb)
|
24
|
-
yaml = YAML.load(to.yaml)
|
25
|
-
assert_equal(2, yaml.size)
|
26
|
-
assert_equal(42, yaml[0]['foo'][0])
|
27
|
-
assert_equal(256, yaml[0]['foo'][1])
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_sorts_keys
|
31
|
-
fb = Factbase.new
|
32
|
-
f = fb.insert
|
33
|
-
f.b = 42
|
34
|
-
f.a = 256
|
35
|
-
f.c = 10
|
36
|
-
yaml = Factbase::ToYAML.new(fb).yaml
|
37
|
-
assert_includes(yaml, "a: 256\n b: 42\n c: 10", yaml)
|
38
|
-
end
|
39
|
-
end
|
data/test/test__helper.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
$stdout.sync = true
|
7
|
-
|
8
|
-
require 'simplecov'
|
9
|
-
require 'simplecov-cobertura'
|
10
|
-
unless SimpleCov.running || ENV['PICKS']
|
11
|
-
SimpleCov.command_name('test')
|
12
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
13
|
-
[
|
14
|
-
SimpleCov::Formatter::HTMLFormatter,
|
15
|
-
SimpleCov::Formatter::CoberturaFormatter
|
16
|
-
]
|
17
|
-
)
|
18
|
-
SimpleCov.minimum_coverage 95
|
19
|
-
SimpleCov.minimum_coverage_by_file 90
|
20
|
-
SimpleCov.start do
|
21
|
-
add_filter 'test/'
|
22
|
-
add_filter 'vendor/'
|
23
|
-
add_filter 'target/'
|
24
|
-
track_files 'lib/**/*.rb'
|
25
|
-
track_files '*.rb'
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
require 'minitest/autorun'
|
30
|
-
require 'minitest/reporters'
|
31
|
-
Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
|
32
|
-
|
33
|
-
require_relative '../lib/factbase'
|
34
|
-
|
35
|
-
# Default methods for all tests.
|
36
|
-
class Factbase::Test < Minitest::Test
|
37
|
-
def fact(map = {})
|
38
|
-
require_relative '../lib/factbase/fact'
|
39
|
-
Factbase::Fact.new(map)
|
40
|
-
end
|
41
|
-
end
|