internal/conformance API

internal/conformance 是各符合性前端共享的结果模型:源位置、带处置类别的逐用例结果、采用固定计数规则的运行汇总,以及确定性的分片选择。frontend/gda_expr、frontend/itl_expr、frontend/mpfr_expr、frontend/testfloat_expr 和 internal/runner_cli 都建立在它之上,并用各自的公共类型包装它的类型。它是一个内部包:Luna-Flow/floating 模块之外的代码无法导入它,其接口也可能在不另行通知的情况下变更。因此本页的示例不参与编译。参见教程和设计页。

导入(仅限模块内部):

import {
  "Luna-Flow/floating/internal/conformance",
}

源位置

SourceLocation

SourceLocation 表示某个具名源中的一个位置。

pub struct SourceLocation {
  // private fields
} derive(Eq, @debug.Debug)

SourceLocation::new

SourceLocation::new(source, line, column?) 创建一个位置。

pub fn SourceLocation::new(String, Int, column? : Int) -> Self

column 默认为 1。行号和列号会被钳制为至少 1,因此位置总是指向一个真实的字符位置。

SourceLocation::source, SourceLocation::line, SourceLocation::column

这些访问器返回各个分量。

pub fn SourceLocation::source(Self) -> String
pub fn SourceLocation::line(Self) -> Int
pub fn SourceLocation::column(Self) -> Int
///|
test "locations are one-based" {
  let location = @conformance.SourceLocation::new("a.txt", 0, column=-3)
  inspect(location.line(), content="1")
  inspect(location.column(), content="1")
}

用例结果

CaseDisposition

CaseDisposition 对一个被选中的用例进行分类。

pub(all) enum CaseDisposition {
  Executable
  Diagnostic(String)
  Legacy(String)
  Unsupported(String)
} derive(Eq, @debug.Debug)
  • Executable:该用例已执行;其 passed 标志有意义。
  • Diagnostic(reason):该用例不是此类测试的有效用例(例如占位行)。
  • Legacy(reason):该用例属于旧版本的语料格式。
  • Unsupported(reason):该用例有效,但实现未提供相应功能。

CaseResult

CaseResult 是单个用例的结果。

pub struct CaseResult {
  // private fields
} derive(Eq, @debug.Debug)

CaseResult::new, CaseResult::executable

CaseResult::new(id, disposition, passed, message?) 构造一个结果;CaseResult::executable(id, passed, message?) 即以 Executable 调用的 new。

pub fn CaseResult::new(String, CaseDisposition, Bool, message? : String) -> Self
pub fn CaseResult::executable(String, Bool, message? : String) -> Self

message 默认为 ""。disposition 与 passed 之间不做一致性检查;汇总只会读取可执行结果的 passed。

CaseResult::id, disposition, passed, message

这些访问器返回存储的字段。

pub fn CaseResult::id(Self) -> String
pub fn CaseResult::disposition(Self) -> CaseDisposition
pub fn CaseResult::passed(Self) -> Bool
pub fn CaseResult::message(Self) -> String

分片

ShardSpec

ShardSpec 是经过校验的(分片数,分片索引)二元组。

pub struct ShardSpec {
  // private fields
} derive(Eq, @debug.Debug)

ShardSpec::try_new, ShardSpec::new

ShardSpec::try_new(count, index) 校验并构造一个分片;ShardSpec::new 在相同情形下以同样的消息中止,而不是返回 Err。

pub fn ShardSpec::try_new(Int, Int) -> Result[Self, String]
pub fn ShardSpec::new(Int, Int) -> Self

错误:当 count <= 0 时为 "shard count must be positive";除非 0 <= index < count,否则为 "shard index must be within shard count"。

ShardSpec::count, ShardSpec::index

这些访问器返回分片数 nn 和索引 ii。

pub fn ShardSpec::count(Self) -> Int
pub fn ShardSpec::index(Self) -> Int

ShardSpec::selects

当序号为 k 的用例属于该分片时,即 k mod n=ik \bmod n = i 时,shard.selects(k) 为真。

pub fn ShardSpec::selects(Self, Int) -> Bool

序号应为非负数(MoonBit 的 % 保留被除数的符号)。

///|
test "round-robin selection" {
  let shard = @conformance.ShardSpec::new(3, 1)
  let picked = [0, 1, 2, 3, 4, 5, 6].filter(k => shard.selects(k))
  debug_inspect(picked, content="[1, 4]")
  inspect(@conformance.ShardSpec::try_new(0, 0) is Err(_), content="true")
}

运行汇总

RunSummary

RunSummary 统计一次运行或一个分片的结果。

pub struct RunSummary {
  // private fields
} derive(Eq, @debug.Debug)

RunSummary::from_results

RunSummary::from_results(total, results) 统计 results,并将 total 记录为分片选择之前的用例数。

pub fn RunSummary::from_results(Int, Array[CaseResult]) -> Self

每个结果只计数一次:Executable 结果根据 passed() 计为通过或失败,其他结果计为跳过,并计入其对应处置类别的计数器。结果会被复制。

RunSummary::merge

RunSummary::merge(parts) 合并各分片的汇总。

pub fn RunSummary::merge(Array[Self]) -> Self

除 total_cases 取各部分的最大值外,所有计数器均求和;结果按 parts 的顺序拼接。空数组给出空汇总。

计数器、results 与 success

这些访问器返回各计数器、结果的副本以及判定结果。

pub fn RunSummary::total_cases(Self) -> Int
pub fn RunSummary::selected_cases(Self) -> Int
pub fn RunSummary::executable_cases(Self) -> Int
pub fn RunSummary::passed_cases(Self) -> Int
pub fn RunSummary::failed_cases(Self) -> Int
pub fn RunSummary::skipped_cases(Self) -> Int
pub fn RunSummary::diagnostic_cases(Self) -> Int
pub fn RunSummary::legacy_cases(Self) -> Int
pub fn RunSummary::unsupported_cases(Self) -> Int
pub fn RunSummary::results(Self) -> Array[CaseResult]
pub fn RunSummary::success(Self) -> Bool

selected_cases 是结果的数量。以下恒等式

selected=executable+skipped,executable=passed+failed,skipped=diagnostic+legacy+unsupported\begin{aligned} \text{selected} &= \text{executable} + \text{skipped}, \\ \text{executable} &= \text{passed} + \text{failed}, \\ \text{skipped} &= \text{diagnostic} + \text{legacy} + \text{unsupported} \end{aligned}

对每个由 from_results 或 merge 构造的汇总都成立。success() 即 failed_cases() == 0;跳过的用例永远不会使其为假。需要更严格判定的前端(itl_expr 在出现诊断时也判为失败)会添加自己的规则。

///|
test "summary counting" {
  let summary = @conformance.RunSummary::from_results(10, [
    @conformance.CaseResult::executable("a", true),
    @conformance.CaseResult::executable("b", false, message="mismatch"),
    @conformance.CaseResult::new("c", @conformance.Unsupported("op"), false),
  ])
  inspect(summary.total_cases(), content="10")
  inspect(summary.selected_cases(), content="3")
  inspect(summary.skipped_cases(), content="1")
  inspect(summary.success(), content="false")
}

trait 实现

相等性与 Debug

这五个类型都派生了 Eq 和 Debug;这些提升的方法比较所有字段并渲染值。新代码请使用 ==、!= 和 debug_inspect。

pub fn SourceLocation::equal(Self, Self) -> Bool
pub fn SourceLocation::not_equal(Self, Self) -> Bool
pub fn SourceLocation::to_repr(Self) -> @debug.Repr
pub fn CaseDisposition::equal(Self, Self) -> Bool
pub fn CaseDisposition::not_equal(Self, Self) -> Bool
pub fn CaseDisposition::to_repr(Self) -> @debug.Repr
pub fn CaseResult::equal(Self, Self) -> Bool
pub fn CaseResult::not_equal(Self, Self) -> Bool
pub fn CaseResult::to_repr(Self) -> @debug.Repr
pub fn ShardSpec::equal(Self, Self) -> Bool
pub fn ShardSpec::not_equal(Self, Self) -> Bool
pub fn ShardSpec::to_repr(Self) -> @debug.Repr
pub fn RunSummary::equal(Self, Self) -> Bool
pub fn RunSummary::not_equal(Self, Self) -> Bool
pub fn RunSummary::to_repr(Self) -> @debug.Repr

完整公共接口

此快照是该包生成的 pkg.generated.mbti。当正文与接口不一致时,以接口为准。

// Generated using `moon info`, DON'T EDIT IT
package "Luna-Flow/floating/internal/conformance"

import {
  "moonbitlang/core/debug",
}

// Values

// Errors

// Types and methods
pub(all) enum CaseDisposition {
  Executable
  Diagnostic(String)
  Legacy(String)
  Unsupported(String)
} derive(Eq, @debug.Debug)
pub fn CaseDisposition::equal(Self, Self) -> Bool
pub fn CaseDisposition::not_equal(Self, Self) -> Bool
pub fn CaseDisposition::to_repr(Self) -> @debug.Repr

pub struct CaseResult {
  // private fields
} derive(Eq, @debug.Debug)
pub fn CaseResult::disposition(Self) -> CaseDisposition
pub fn CaseResult::equal(Self, Self) -> Bool
pub fn CaseResult::executable(String, Bool, message? : String) -> Self
pub fn CaseResult::id(Self) -> String
pub fn CaseResult::message(Self) -> String
pub fn CaseResult::new(String, CaseDisposition, Bool, message? : String) -> Self
pub fn CaseResult::not_equal(Self, Self) -> Bool
pub fn CaseResult::passed(Self) -> Bool
pub fn CaseResult::to_repr(Self) -> @debug.Repr

pub struct RunSummary {
  // private fields
} derive(Eq, @debug.Debug)
pub fn RunSummary::diagnostic_cases(Self) -> Int
pub fn RunSummary::equal(Self, Self) -> Bool
pub fn RunSummary::executable_cases(Self) -> Int
pub fn RunSummary::failed_cases(Self) -> Int
pub fn RunSummary::from_results(Int, Array[CaseResult]) -> Self
pub fn RunSummary::legacy_cases(Self) -> Int
pub fn RunSummary::merge(Array[Self]) -> Self
pub fn RunSummary::not_equal(Self, Self) -> Bool
pub fn RunSummary::passed_cases(Self) -> Int
pub fn RunSummary::results(Self) -> Array[CaseResult]
pub fn RunSummary::selected_cases(Self) -> Int
pub fn RunSummary::skipped_cases(Self) -> Int
pub fn RunSummary::success(Self) -> Bool
pub fn RunSummary::to_repr(Self) -> @debug.Repr
pub fn RunSummary::total_cases(Self) -> Int
pub fn RunSummary::unsupported_cases(Self) -> Int

pub struct ShardSpec {
  // private fields
} derive(Eq, @debug.Debug)
pub fn ShardSpec::count(Self) -> Int
pub fn ShardSpec::equal(Self, Self) -> Bool
pub fn ShardSpec::index(Self) -> Int
pub fn ShardSpec::new(Int, Int) -> Self
pub fn ShardSpec::not_equal(Self, Self) -> Bool
pub fn ShardSpec::selects(Self, Int) -> Bool
pub fn ShardSpec::to_repr(Self) -> @debug.Repr
pub fn ShardSpec::try_new(Int, Int) -> Result[Self, String]

pub struct SourceLocation {
  // private fields
} derive(Eq, @debug.Debug)
pub fn SourceLocation::column(Self) -> Int
pub fn SourceLocation::equal(Self, Self) -> Bool
pub fn SourceLocation::line(Self) -> Int
pub fn SourceLocation::new(String, Int, column? : Int) -> Self
pub fn SourceLocation::not_equal(Self, Self) -> Bool
pub fn SourceLocation::source(Self) -> String
pub fn SourceLocation::to_repr(Self) -> @debug.Repr

// Type aliases

// Traits