रेंडरिंगhi

Errors and testing

Error handling#

Faber तीन संबंधित विचारों को अलग रखता है, जिन्हें कई भाषाएँ एक ही रूप में मिला देती हैं:

निर्माणअर्थ
→ Tसामान्य सफलता रिटर्न चैनल
T ∪ शून्य_मानसफलता मान डोमेन में अनुपस्थिति
⇥ Eत्रुटियों के लिए पुनर्प्राप्त करने योग्य वैकल्पिक-निकास चैनल

सामान्य रिटर्न#

फलन porta(संख्या x) → संख्या {
    यदि x ≺ 0 अतः लौटाओ 0
    लौटाओ x * 2
}

विफल हो सकने वाले फ़ंक्शन#

जब कोई फ़ंक्शन त्रुटि चैनल के माध्यम से बाहर निकल सकता हो, तब ⇥ का उपयोग करें:

फलन divide(संख्या a, संख्या b) → संख्या ⇥ पाठ {
    यदि b ≡ 0 {
        इधरफेंको "division by zero"
    }
    लौटाओ a / b
}

थ्रो करना — इधरफेंको#

इधरफेंको त्रुटि चैनल पर कोई मान भेजता है:

फलन exigePositivum(संख्या value) → रिक्त ⇥ पाठ {
    यदि value ≺ 0 {
        इधरफेंको "negative value"
    }
}

रिकवरी — करो / पकड़ो#

कॉलर करो ब्लॉक और पकड़ो हैंडलर के साथ स्थानीय रूप से रिकवरी करते हैं:

फलन divide(संख्या a, संख्या b) → संख्या {
    यदि b ≡ 0 अतः लौटाओ 0
    लौटाओ a / b
}

फलन tutum(संख्या a, संख्या b) → संख्या {
    करो {
        लौटाओ divide(a, b)
    }
    पकड़ो err {
        चेताओ err
        लौटाओ 0
    }
}

किसी विफल हो सकने वाले → T ⇥ E फ़ंक्शन को सीधे कॉल करना सामान्य एक्सप्रेशन नहीं है। ऐसे कॉल को सक्रिय करो / पकड़ो सीमा के भीतर रखें।

इनलाइन रूपांतरण रिकवरी#

⊥, ↦ रूपांतरणों पर इनलाइन रिकवरी मान भी निर्दिष्ट कर सकता है:

आरंभ {
    स्थिर पाठ raw ← "42"
    स्थिर _ n ← raw ↦ संख्या ⊥ 0
}

केवल-प्रभाव वाला विफल हो सकने वाला फ़ंक्शन#

ऐसे फ़ंक्शन जो त्रुटि देते हैं, लेकिन सफलता मान वापस नहीं करते, उनमें → T छोड़ दें:

फलन exigePositivum(संख्या value) → रिक्त ⇥ पाठ {
    यदि value ≺ 0 {
        इधरफेंको "negative value"
    }
}

वर्तमान स्थिति#

→, लौटाओ, ⇥, इधरफेंको, और करो / पकड़ो लाइव व्याकरण और चेकर सतहें हैं। पूर्ण ⇥ / इधरफेंको / पकड़ो रनटाइम व्यवहार के लिए Rust और Go लोअरिंग में अभी बैकएंड की कमी है — ये टाइप-चेकिंग पास करते हैं, लेकिन अभी सभी लक्ष्यों के लिए विफल हो सकने वाला रनटाइम कोड उत्पन्न नहीं करते।

Inline testing#

Faber में भाषा के भीतर ही निर्मित एक प्रथम-श्रेणी परीक्षण फ्रेमवर्क है, जिसमें तीन कीवर्ड हैं: परीक्षणसमूह एक परीक्षण सूट घोषित करता है, परीक्षण एकल परीक्षण केस घोषित करता है, और पुष्टि किसी शर्त की पुष्टि करता है। परीक्षण उसी फ़ाइल में रहते हैं जिसमें उनका परीक्षण किया जाने वाला कोड होता है, faber test के माध्यम से चलते हैं, और प्रोडक्शन कोड के समान कंपाइलर पाइपलाइन का समर्थन करते हैं — लोकेल-अवेयर, प्रकार-जाँचे हुए और बहु-लक्ष्यीय।

तीन कीवर्ड#

कीवर्डभूमिकालगभग समतुल्य
परीक्षणसमूहनामित परीक्षण सूट घोषित करता हैdescribe, #[cfg(test)] mod
परीक्षणएकल परीक्षण केस घोषित करता हैit, #[test]
पुष्टिरनटाइम पर किसी शर्त की पुष्टि करता हैassert!, assert_eq!

परीक्षणसमूह — परीक्षण सूट#

परीक्षणसमूह ब्लॉक संबंधित परीक्षण मामलों को एक साथ समूहित करता है। परीक्षणों को पदानुक्रम के अनुसार व्यवस्थित करने के लिए सूट को नेस्ट किया जा सकता है:

परीक्षणसमूह "arithmetica" {
    परीक्षण "unum plus unum" {
        पुष्टि 1 + 1 ≡ 2
    }

    परीक्षण "multiplicatio" {
        पुष्टि 3 * 4 ≡ 12
    }

    परीक्षणसमूह "implicata" {
        परीक्षण "comparatio" {
            स्थिर _ x ← 10
            पुष्टि x ≥ 10
        }
    }
}

परीक्षण — परीक्षण केस#

परीक्षण ब्लॉक में परीक्षण का तर्क होता है। इसमें कोई भी Faber कोड — वैरिएबल बाइंडिंग, फ़ंक्शन कॉल, नियंत्रण प्रवाह — इस्तेमाल किया जा सकता है और इसका अंत एक या अधिक पुष्टि पुष्टियों के साथ होता है। चयनात्मक निष्पादन के लिए परीक्षणों पर वैकल्पिक टैग मार्कर लगाया जा सकता है:

परीक्षण "echo formats operands with one space" टैग "coreutils" {
    पुष्टि echo_textus(["hello", "world"]) ≡ "hello world"
}

पुष्टि — पुष्टि#

पुष्टि किसी बूलियन अभिव्यक्ति का मूल्यांकन करता है और उसके असत्य होने पर विफलता की सूचना देता है। विफलता के समय संदर्भ देने के लिए वैकल्पिक संदेश स्ट्रिंग दी जा सकती है:

आरंभ {
    स्थिर _ x ← 10

    # Simple assertion
    पुष्टि x ≻ 0

    # With custom message
    पुष्टि x ≡ 10 मरोजाओ "x decem esse debet"

    # Multiple assertions in sequence
    स्थिर _ नाम ← "Marcus"
    पुष्टि नाम ≡ "Marcus"
    पुष्टि नाम ≠ "" मरोजाओ "nomen vacuum non sit"
}

कार्यप्रवाह#

परीक्षण faber test कमांड के माध्यम से चलते हैं:

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

क्योंकि परीक्षण उसी .fab फ़ाइल में स्रोत कोड के साथ रहते हैं, इसलिए अलग परीक्षण डायरेक्टरी संरचना, परीक्षण मॉड्यूल घोषणा या परीक्षण और प्रोडक्शन बिल्ड के बीच अलग बिल्ड स्क्रिप्ट की आवश्यकता नहीं होती। कंपाइलर इस्तेमाल किए गए कीवर्ड के आधार पर यह जानता है कि कौन-से ब्लॉक परीक्षण कोड हैं और कौन-से प्रोडक्शन कोड — परीक्षणसमूह और परीक्षण को पार्स किया जाता है, लेकिन प्रोडक्शन बिल्ड से बाहर रखा जाता है।

वास्तविक उदाहरण#

coreutils का echo पैकेज परीक्षण फ्रेमवर्क को व्यवहार में प्रदर्शित करता है। परीक्षण उसी फ़ाइल में इम्प्लीमेंटेशन के साथ रहते हैं और विकल्प पार्सिंग, एस्केप विस्तार तथा किनारी स्थितियों को कवर करते हैं:

परीक्षणसमूह "echo formatting" टैग "coreutils" {
    परीक्षण "empty operands format as empty text" {
        स्थिर सूची<पाठ> words ← खाली
        पुष्टि echo_textus(words) ≡ ""
    }

    परीक्षण "single operand is unchanged" {
        पुष्टि echo_textus(["hello"]) ≡ "hello"
    }

    परीक्षण "-E is a leading no-op option" {
        पुष्टि echo_textus(["-E", "hello", "world"]) ≡ "hello world"
    }

    परीक्षण "-n suppresses the trailing newline flag" {
        पुष्टि echo_novam_lineam(["-n", "hello"]) ≡ असत्य
    }

    परीक्षण "-e expands the declared escape subset" {
        पुष्टि echo_textus(["-e", "a\\nb"]) ≡ "a\nb"
        पुष्टि echo_textus(["-e", "a\\tb"]) ≡ "a\tb"
    }
}

डिज़ाइन नोट्स#

कई डिज़ाइन विकल्प Faber के परीक्षण फ्रेमवर्क को पारंपरिक तरीकों से अलग बनाते हैं:

  • अलग परीक्षण बाइनरी नहीं। परीक्षण अलग कंपाइलेशन लक्ष्य नहीं, बल्कि उसी स्रोत फ़ाइल में घोषणाएँ हैं। कंपाइलर परीक्षण ब्लॉकों को प्रोडक्शन आउटपुट से फ़िल्टर कर देता है।
  • डायरेक्टरी नहीं, टैग। परीक्षण डायरेक्टरी संरचना के बजाय टैग मार्करों के आधार पर व्यवस्थित किए जाते हैं। किसी परीक्षण को स्थान बदले बिना कई संगठनात्मक अक्षों में शामिल किया जा सकता है।
  • पूर्ण कंपाइलर पाइपलाइन। परीक्षणों की प्रकार-जाँच और विश्लेषण किया जाता है तथा वे लोकेल-अवेयर होते हैं — परीक्षण आउटपुट पर भी वही --reader-locale फ़्लैग लागू होता है।
  • बहु-लक्ष्य। परीक्षण पैकेज द्वारा लक्षित बैकएंड के माध्यम से चलते हैं — faber test --interpret के लिए MIR स्टेपर और faber test के लिए कंपाइल्ड Rust।
  • नेस्टेड सूट। परीक्षणसमूह ब्लॉक नेस्ट किए जा सकते हैं और उस कोड की संरचना को प्रतिबिंबित करते हैं जिसका वे परीक्षण करते हैं।

संदर्भ#

  1. examples/corpus/probandum/ — परीक्षणसमूह उदाहरण फ़ाइलें
  2. examples/corpus/proba/ — परीक्षण उदाहरण फ़ाइलें
  3. examples/corpus/adfirma/ — पुष्टि उदाहरण फ़ाइलें
  4. examples/coreutils/packages/echo/src/main.fab — टैग के साथ वास्तविक उपयोग