Skip to content

Commit

Permalink
fix(数据结构): 🐛 修复隐含漏洞,提高代码覆盖率
Browse files Browse the repository at this point in the history
  • Loading branch information
ARCJ137442 committed Sep 1, 2023
1 parent 8db02e7 commit 07f21ea
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 36 deletions.
63 changes: 39 additions & 24 deletions src/Narsese/Sentences/stamp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
# 导出
export STAMP_TIME_TYPE, TIME_ETERNAL
export AbstractStamp, Stamp
export StampBasic
export StampBasic, StampPythonic
export get_evidential_base, get_creation_time, get_put_in_time, get_occurrence_time


"""
Expand Down Expand Up @@ -60,6 +61,26 @@ const STAMP_TIME_TYPE::DataType = UInt # 根据PyNARS的语法要求,改为「
"""
TIME_ETERNAL::STAMP_TIME_TYPE = typemin(STAMP_TIME_TYPE)

# 方法集 #

"各个抽象Getter"
get_evidential_base(s::Stamp) = error("$(typeof(s)): 未实现的`get_evidential_base`方法!")
get_creation_time(s::Stamp) = error("$(typeof(s)): 未实现的`get_creation_time`方法!")
get_put_in_time(s::Stamp) = error("$(typeof(s)): 未实现的`get_put_in_time`方法!")
get_occurrence_time(s::Stamp) = error("$(typeof(s)): 未实现的`get_occurrence_time`方法!")

"重定向运算符"
@inline Base.:(==)(s1::Stamp, s2::Stamp) = Base.isequal(s1, s2)
"判等の法:各个属性相等"
@inline Base.isequal(s1::Stamp, s2::Stamp) = (
get_tense(s1) == get_tense(s2) && # 时态相等
get_evidential_base(s1) == get_evidential_base(s2) &&
get_creation_time(s1) == get_creation_time(s2) &&
get_put_in_time(s1) == get_put_in_time(s2) &&
get_occurrence_time(s1) == get_occurrence_time(s2)
)

# 具体实现

"""
源:OpenNARS
Expand Down Expand Up @@ -121,6 +142,11 @@ struct StampBasic{tense <: AbstractTense} <: AbstractStamp
end
end

get_evidential_base(s::StampBasic) = s.evidential_base
get_creation_time(s::StampBasic) = s.creation_time
get_put_in_time(s::StampBasic) = s.put_in_time
get_occurrence_time(s::StampBasic) = s.occurrence_time

"类型参数の默认值:无时态⇒「永恒」时态"
StampBasic(args...) = StampBasic{Eternal}(args...)

Expand Down Expand Up @@ -211,6 +237,12 @@ struct StampPythonic <: AbstractStamp
end
end

get_evidential_base(s::StampPythonic) = s.evidential_base
get_creation_time(s::StampPythonic) = s.creation_time
get_put_in_time(s::StampPythonic) = s.put_in_time
get_occurrence_time(s::StampPythonic) = s.occurrence_time


begin "方法集"

# 【20230815 16:33:51】函数「get_tense」已在「methods.jl」中定义
Expand All @@ -221,7 +253,9 @@ begin "方法集"
"""
获取时态
"""
@inline get_tense(s::StampBasic{S}) where {S} = S
@inline (get_tense(::StampBasic{T})::TTense) where {T} = T
"Python化的「绝对时态」总是「永恒」"
@inline get_tense(s::StampPythonic)::TTense = TenseEternal
"Python化的「相对时态」:与「发生时间」对比"
@inline get_tense(s::StampPythonic, reference_time::STAMP_TIME_TYPE)::TTense = (
reference_time == s.occurrence_time ?
Expand All @@ -231,6 +265,8 @@ begin "方法集"
TenseFuture
)
)
"类型自动转换"
@inline get_tense(s::StampPythonic, reference_time::Integer)::TTense = get_tense(s, STAMP_TIME_TYPE(reference_time))

"""
(用于「基础时间戳」)是否是由「固定时刻」
Expand All @@ -243,26 +279,5 @@ begin "方法集"
)
"【20230815 23:45:19】Python版的暂且恒为true,因为并无「固定的时态」一说"
@inline is_fixed_occurrence_time(s::StampPythonic) = true

"""
判等の法:相等@各个属性
"""
@inline Base.:(==)(s1::StampBasic, s2::StampBasic)::Bool = (
typeof(s1) == typeof(s2) && # 时态相等
s1.evidential_base == s2.evidential_base &&
s1.creation_time == s2.creation_time &&
s1.put_in_time == s2.put_in_time &&
s1.occurrence_time == s2.occurrence_time
)

"""
判等の法:相等@各个属性
"""
@inline Base.:(==)(s1::StampPythonic, s2::StampPythonic)::Bool = (
s1.evidential_base == s2.evidential_base &&
s1.creation_time == s2.creation_time &&
s1.put_in_time == s2.put_in_time &&
s1.occurrence_time == s2.occurrence_time
)

end
end
4 changes: 2 additions & 2 deletions src/Narsese/Sentences/truth.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ const Truth = ATruth = AbstractTruth
# 抽象类方法 #

"获取频率f"
get_f(t::Truth) = error("$t: 未实现的`get_f`方法!")
get_f(t::Truth) = error("$(typeof(t)): 未实现的`get_f`方法!")
"获取信度c"
get_c(t::Truth) = error("$t: 未实现的`get_c`方法!")
get_c(t::Truth) = error("$(typeof(t)): 未实现的`get_c`方法!")

"""
判等の法:相等@f,c
Expand Down
6 changes: 3 additions & 3 deletions src/Narsese/Tasks/budget.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ const Budget = ABudget = AbstractBudget
# 抽象类方法 #

"获取优先级p"
get_p(b::Budget) = error("$b: 未实现的`get_p`方法!")
get_p(b::Budget) = error("$(typeof(b)): 未实现的`get_p`方法!")
"获取耐久度d"
get_d(b::Budget) = error("$b: 未实现的`get_d`方法!")
get_d(b::Budget) = error("$(typeof(b)): 未实现的`get_d`方法!")
"获取质量q"
get_q(b::Budget) = error("$b: 未实现的`get_q`方法!")
get_q(b::Budget) = error("$(typeof(b)): 未实现的`get_q`方法!")

"""
判等の法:相等@p,d,q
Expand Down
2 changes: 1 addition & 1 deletion src/Narsese/Terms/methods.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ begin "NAL信息支持"
- 等价于:虚方法/抽象方法
- 需要被子类实现
"""
@inline get_syntactic_complexity(::Term) = error("未定义的计算!")
@inline get_syntactic_complexity(t::Term) = error("$(typeof(t))未定义的计算!")

"""
(默认)原子の复杂度 = 1
Expand Down
11 changes: 8 additions & 3 deletions src/Narsese/use_strict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ end
# 临时定义陈述合法性:改变「内联合法性检查」逻辑
"继承&相似⇒是否为「一等公民」"
@inline function check_valid(t::Statement{<:TermBasedSTs})
ϕ1(t) ϕ2(t) && ϕ1(t) isa FOTerm && ϕ2(t) isa FOTerm
ϕ1(t) ϕ2(t) &&
ϕ1(t) isa FOTerm &&
ϕ2(t) isa FOTerm
end

"继承&相似⇒是否为「一等公民」"
Expand All @@ -65,7 +67,9 @@ end

"蕴含&等价⇒是否为「陈述词项」"
@inline function check_valid(t::Statement{<:StatementBasedSTs})
ϕ1(t) ϕ2(t) && ϕ1(t) isa AbstractStatement && ϕ2(t) isa AbstractStatement
ϕ1(t) ϕ2(t) &&
ϕ1(t) isa StatementLike &&
ϕ2(t) isa StatementLike
end

"蕴含&等价⇒是否为「陈述词项」"
Expand All @@ -79,7 +83,8 @@ end

"陈述逻辑集、陈述时序集:词项数>1 && 不支持「非陈述词项」"
@inline function check_valid(t::ACompound{<:StatementBasedCTs})
length(t) > 1 && all(term isa StatementLike for term in t)
length(t) > 1 &&
all(term isa StatementLike for term in t)
end
"陈述逻辑集、陈述时序集:词项数>1 && 不支持「非陈述词项」"
@inline function check_valid_explainable(t::ACompound{<:StatementBasedCTs})
Expand Down
17 changes: 16 additions & 1 deletion src/Util/Util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
module Util

export UNothing
export @reverse_dict_content, @redirect_SRS, @expectedError
export @reverse_dict_content, @redirect_SRS, @hasError, @expectedError
export match_first, match_first_view
export allproperties, allproperties_generator, allproperties_named, allproperties_named_generator
export empty_content
Expand Down Expand Up @@ -35,6 +35,21 @@ macro redirect_SRS(para::Expr, code::Expr)
return redirect_SRS(para, code)
end

"【用于调试】判断「是否出错」(仿官方库show语法)"
macro hasError(exs...)
Expr(:block, [ # 生成一个block,并使用列表推导式自动填充args
quote
try
$(esc(ex))
false
catch e
true
end
end
for ex in exs
]...) # 别忘展开
end

"【用于调试】判断「期望出错」(仿官方库show语法)"
macro expectedError(exs...)
Expr(:block, [ # 生成一个block,并使用列表推导式自动填充args
Expand Down
7 changes: 7 additions & 0 deletions test/test_construction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@

@show w i d q o

p = PlaceHolder()
@test w == Word(:词项)::Word
@test i == IVar(:独立变量)::Variable{VTIndependent}
@test d == DVar(:非独变量)::Variable{VTDependent}
@test q == QVar(:查询变量)::Variable{VTQuery}
@test p == PlaceHolder()::PlaceHolder
@test o == Operator(:操作)::Operator
@test n == Interval(+137)::Interval

# 像占位符
@test p == placeholder
@test nameof(p) == Symbol()
@test nameof_string(p) == ""

# 词项集
exSet = (w, d, o)
inSet = (n, q, i)
Expand Down
2 changes: 1 addition & 1 deletion test/test_methods_arrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@test length(A) == 1

# 测试原子的索引函数
@test getindex(A) == A[] == :A
@test getindex(A) == A[] == A[typemax(Int)] == A[typemin(Int)] == :A

# 测试除差、像以外的所有复合词项
for compoundType::Type in [TermProduct, ExtSet, IntSet, ExtIntersection, IntIntersection]
Expand Down
41 changes: 40 additions & 1 deletion test/test_methods_nal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@
(AB) in terms_ && (BC) in terms_ &&
((AB)(BC)) in terms_

# 获取所有索引
t = ExtSet(A,B,C)
@test eachindex(t) == Base.OneTo(3)
@test nextind(t, 1) == 2
@test prevind(t, 2) == 1

# 是否可交换 #
@test !is_commutative(StatementTypeInheritance)
@test !is_commutative(StatementTypeImplication)
@test is_commutative(StatementTypeSimilarity)
@test is_commutative(StatementTypeEquivalence)


@test !is_commutative(Term) # 默认不可交换
@test !is_commutative(TermProduct)
@test !is_commutative(ExtImage)
@test !is_commutative(IntDiff)
Expand All @@ -42,6 +49,7 @@

# 是否可重复:默认是`!(是否可交换)`,但**不用于判断陈述** #

@test is_repeatable(Term) # 默认可重复
@test is_repeatable(TermProduct)
@test is_repeatable(ExtImage)
@test is_repeatable(SeqConjunction)
Expand Down Expand Up @@ -127,4 +135,35 @@

@test EquivalenceRetrospective(AB, BA) == EquivalencePredictive(BA, AB)

# 语句&任务 #

# 时间戳 #

sb = StampBasic()
sp1 = StampPythonic()

@test sb == sp1 # 默认值应该相等
@test sb !== sp1 # 不全等

sp2 = StampPythonic(occurrence_time = 1)
# 相对时序
@test get_tense(sp2) == Eternal # 默认永恒
@test get_tense(sp2, 0) == Future # sp2 是 0 的未来
@test get_tense(sp2, 1) == Present # sp2 是 1 的现在
@test get_tense(sp2, 2) == Past # sp2 是 2 的过去

@test sp2 == deepcopy(sp2)
@test sp1 != sp2

# 方法重定向
for t in test_set.tasks, method_name in [:get_term, :get_stamp, :get_tense, :get_punctuation, :get_truth, :get_syntactic_complexity]
@test @eval $method_name($t) == $method_name(get_sentence($t))
end
for t in test_set.tasks, method_name in [:get_p, :get_d, :get_q]
@test @eval $method_name($t) == $method_name(get_budget($t))
end
for t in test_set.sentences, method_name in [:get_syntactic_complexity]
@test @eval $method_name($t) == $method_name(get_term($t))
end

end
11 changes: 11 additions & 0 deletions test/test_methods_validity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,15 @@
@test @expectedError ParConjunction(AB, CD, AD, Do, BC, w)
@test @expectedError SeqConjunction(AB, Do, BC, AD, CD, w)

# 所有词项的「可解释🆚非解释」「内部🆚外部」严格性应该相互等价
for term::Term in test_set.terms
@show term
@test (
check_valid(term) ==
!(@hasError check_valid_explainable(term)) ==
check_valid_external(term) ==
!(@hasError check_valid_external_explainable(term))
)
end

end
3 changes: 3 additions & 0 deletions test/test_narsese.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

# 类型 #
include("test_types.jl")

# API #
include("test_narsese_api.jl")

# 词项与数组等可迭代对象的联动方法 #
include("test_methods.jl")
Expand Down
35 changes: 35 additions & 0 deletions test/test_narsese_api.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
(@isdefined JuNarsese) || include("commons.jl") # 已在此中导入JuNarsese、Test

# 词项接口:用于后续扩展自定义词项/语句/任务 #
@testset "Narsese/API" begin

# 定义几个没实现方法的抽象类型,以便测试在「调用未实现方法的报错」 #
struct TestTerm <: Term end
struct TestTruth <: Truth end
struct TestBudget <: Budget end
struct TestStamp <: Stamp end

t = TestTerm()
tt = TestTruth()
ts = TestStamp()
tb = TestBudget()

@test @expectedError get_syntactic_complexity(t)

@test @expectedError get_f(tt)
@test @expectedError get_c(tt)

@test @expectedError get_p(tb)
@test @expectedError get_d(tb)
@test @expectedError get_q(tb)

@test @expectedError get_evidential_base(ts)
@test @expectedError get_creation_time(ts)
@test @expectedError get_put_in_time(ts)
@test @expectedError get_occurrence_time(ts)

# 测试一些「抽象词项的默认值」 #
@test !is_commutative(t) # 默认不可交换
@test is_repeatable(t) # 默认可重复

end

0 comments on commit 07f21ea

Please sign in to comment.