Kết xuấtvi

Errors and testing

Error handling#

Faber tách biệt ba ý liên quan mà nhiều ngôn ngữ gộp vào cùng một dạng:

Cấu trúcÝ nghĩa
→ TKênh trả về thành công thông thường
T ∪ nihilSự vắng mặt trong miền giá trị thành công
⇥ EKênh thoát thay thế có thể phục hồi dành cho lỗi

Trả về thông thường#

hàm porta(số x)  số {
    nếu x ≺ 0 do_đó trả 0
    trả x * 2
}

Hàm có thể thất bại#

Dùng khi một hàm có thể thoát qua kênh lỗi:

hàm divide(số a, số b)  sốvăn_bản {
    nếu b  0 {
        ném "division by zero"
    }
    trả a / b
}

Ném — iace#

iace gửi một giá trị qua kênh lỗi:

hàm exigePositivum(số value)  trốngvăn_bản {
    nếu value ≺ 0 {
        ném "negative value"
    }
}

Phục hồi — fac / cape#

Bên gọi phục hồi cục bộ bằng khối làm và trình xử lý bắt:

hàm divide(số a, số b)  số {
    nếu b  0 do_đó trả 0
    trả a / b
}

hàm tutum(số a, số b)  số {
    làm {
        trả divide(a, b)
    }
    bắt err {
        cảnh_báo err
        trả 0
    }
}

Một lời gọi hàm có thể thất bại trực tiếp không phải là một biểu thức thông thường. Đặt lời gọi đến các hàm → T ⇥ E bên trong một ranh giới làm / bắt đang hoạt động.

Phục hồi chuyển đổi nội tuyến#

cũng có thể chỉ định một giá trị phục hồi nội tuyến trên các phép chuyển đổi :

hằng văn_bản raw  "42"

hằng số n  raw ↦ số0

Hàm có thể thất bại chỉ tạo hiệu ứng#

Đối với các hàm có lỗi nhưng không trả về giá trị thành công, hãy bỏ qua → T:

hàm exigePositivum(số value)  trốngvăn_bản {
    nếu value ≺ 0 {
        ném "negative value"
    }
}

Trạng thái hiện tại#

, trả, , iacelàm / bắt là các bề mặt ngữ pháp và trình kiểm tra đang hoạt động. Việc hạ cấp cho Rust và Go đối với toàn bộ hành vi thời gian chạy của / iace / bắt vẫn còn thiếu ở phần backend — các cấu trúc này vượt qua bước kiểm tra kiểu, nhưng hiện chưa phát sinh mã thời gian chạy có thể thất bại cho tất cả các đích.

Inline testing#

Faber có một framework kiểm thử hạng nhất được tích hợp sẵn trong ngôn ngữ, với ba từ khóa: probandum khai báo một nhóm kiểm thử, proba khai báo một ca kiểm thử đơn lẻ, và adfirma khẳng định một điều kiện. Các bài kiểm thử nằm trong cùng tệp với mã mà chúng kiểm thử, được chạy bằng faber test, và sử dụng cùng pipeline biên dịch như mã sản phẩm — nhận biết locale, kiểm tra kiểu, và hỗ trợ nhiều đích.

Ba từ khóa#

Từ khóaVai tròTương đương gần đúng
probandumKhai báo một nhóm kiểm thử có têndescribe, #[cfg(test)] mod
probaKhai báo một ca kiểm thử đơn lẻit, #[test]
adfirmaKhẳng định một điều kiện tại thời điểm chạyassert!, assert_eq!

probandum — nhóm kiểm thử#

Một khối probandum nhóm các ca kiểm thử có liên quan. Các nhóm có thể lồng nhau để tổ chức kiểm thử theo cấp bậc:

kiểm_thử "unum plus unum" {
    khẳng_định 1 + 1  2
}

kiểm_thử "multiplicatio" {
    khẳng_định 3 * 4  12
}

kiểm_thử "comparatio" {
    hằng số x  10
    khẳng_định x  10
}

proba — ca kiểm thử#

Một khối proba chứa logic kiểm thử. Khối này có thể sử dụng mọi mã Faber — liên kết biến, lời gọi hàm, luồng điều khiển — và kết thúc bằng một hoặc nhiều khẳng định adfirma. Có thể gắn thẻ cho các bài kiểm thử bằng một marker tag tùy chọn để chạy có chọn lọc:

proba "echo formats operands with one space" tag "coreutils" {
    adfirma echo_textus(["hello", "world"]) ≡ "hello world"
}

adfirma — khẳng định#

adfirma đánh giá một biểu thức boolean và báo lỗi nếu biểu thức đó sai. Một chuỗi thông báo tùy chọn cung cấp ngữ cảnh khi xảy ra lỗi:

bắt_đầu {
    hằng số x  10

    # Simple assertion
    khẳng_định x ≻ 0

    # With custom message
    khẳng_định x  10 secus "x decem esse debet"

    # Multiple assertions in sequence
    hằng văn_bản nomen  "Marcus"
    khẳng_định nomen  "Marcus"
    khẳng_định nomen  "" secus "nomen vacuum non sit"
}

Quy trình#

Các bài kiểm thử được chạy thông qua lệnh faber test:

faber test                        # run all tests in the current package
faber test examples/coreutils/packages/echo  # run tests for a specific package

Vì các bài kiểm thử nằm cạnh mã nguồn trong cùng tệp .fab, nên không có cấu trúc thư mục kiểm thử riêng, không cần khai báo module kiểm thử, và cũng không có sự khác biệt trong script build giữa bản build kiểm thử và bản build sản phẩm. Trình biên dịch nhận biết khối nào là mã kiểm thử và khối nào là mã sản phẩm dựa trên các từ khóa được sử dụng — probandumproba được phân tích cú pháp nhưng được loại khỏi các bản build sản phẩm.

Ví dụ thực tế#

Gói coreutils echo minh họa framework kiểm thử trong thực tế. Các bài kiểm thử nằm trong cùng tệp với phần triển khai, bao phủ việc phân tích tùy chọn, mở rộng escape và các trường hợp biên:

probandum "echo formatting" tag "coreutils" {
    proba "empty operands format as empty text" {
        fixum lista<textus> words ← vacua
        adfirma echo_textus(words) ≡ ""
    }

    proba "single operand is unchanged" {
        adfirma echo_textus(["hello"]) ≡ "hello"
    }

    proba "-E is a leading no-op option" {
        adfirma echo_textus(["-E", "hello", "world"]) ≡ "hello world"
    }

    proba "-n suppresses the trailing newline flag" {
        adfirma echo_novam_lineam(["-n", "hello"]) ≡ falsum
    }

    proba "-e expands the declared escape subset" {
        adfirma echo_textus(["-e", "a\\nb"]) ≡ "a\nb"
        adfirma echo_textus(["-e", "a\\tb"]) ≡ "a\tb"
    }
}

Ghi chú thiết kế#

Một số lựa chọn thiết kế làm framework kiểm thử của Faber khác với các phương pháp thông thường:

  • Không có binary kiểm thử riêng. Bài kiểm thử là các khai báo trong cùng tệp nguồn, không phải một đích biên dịch riêng. Trình biên dịch lọc các khối kiểm thử khỏi đầu ra sản phẩm.
  • Dùng thẻ, không dùng thư mục. Bài kiểm thử được tổ chức bằng các marker tag thay vì cấu trúc thư mục. Một bài kiểm thử có thể thuộc nhiều trục tổ chức mà không cần di chuyển.
  • Đầy đủ pipeline biên dịch. Bài kiểm thử được kiểm tra kiểu, phân tích và nhận biết locale — cùng cờ --reader-locale cũng áp dụng cho đầu ra kiểm thử.
  • Nhiều đích. Bài kiểm thử chạy qua backend mà gói nhắm tới — bộ bước MIR cho faber test --interpret, Rust đã biên dịch cho faber test.
  • Nhóm lồng nhau. Các khối probandum có thể lồng nhau, phản ánh cấu trúc của mã mà chúng kiểm thử.

Tham khảo#

  1. examples/corpus/probandum/ — các tệp ví dụ probandum
  2. examples/corpus/proba/ — các tệp ví dụ proba
  3. examples/corpus/adfirma/ — các tệp ví dụ adfirma
  4. examples/coreutils/packages/echo/src/main.fab — cách sử dụng thực tế với các thẻ