Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ฮาร์เนสทดสอบ .wast

ไฟล์ .wast ถูกใช้เพื่อการทดสอบและช่วยให้นักพัฒนาเขียนเทสต์ได้ง่ายขึ้น เราใช้ไฟล์ .wast เพื่อเข้ารหัสแอสเซอร์ชันที่ควรผ่านเมื่อรันโมดูล wasm ที่ทำ instrumentation แล้ว

การเขียนเทสต์ .wast

โครงสร้างระดับสูงมีหน้าตาดังนี้:

<module_in_wat>

;; WHAMM --> <some_oneline_whamm_script>
<whamm0_assertion0> ;; The first assertion for the first whamm script
<whamm0_assertion1> ;; The second assertion for the first whamm script

;; WHAMM --> <some_oneline_whamm_script>
<whamm1_assertion0> ;; The first assertion for the second whamm script
<whamm1_assertion1> ;; The second assertion for the second whamm script
<whamm2_assertion1> ;; The third assertion for the second whamm script

โมดูลที่เข้ารหัสในสคริปต์ด้านบนจะถูกใช้กับทุกกลุ่ม whamm/แอสเซอร์ชันที่ตามมา เพื่อยืนยันว่าแอสเซอร์ชันทั้งหมดล้มเหลวก่อนทำ instrumentation ไฟล์ .wast ใหม่ 5 ไฟล์จะถูกสร้างขึ้นด้วยโมดูลต้นฉบับและรันบนอินเทอร์พรีเตอร์ที่กำหนดค่าไว้ และเพื่อยืนยันว่าแอสเซอร์ชันทั้งหมดผ่านหลังทำ instrumentation ไฟล์ .wast ใหม่ 2 ไฟล์จะถูกสร้างขึ้น หนึ่งไฟล์ต่อสคริปต์ whamm ที่ระบุ โดยรวมแอสเซอร์ชันไว้ใต้สคริปต์ whamm ที่เกี่ยวข้อง

ด้านล่างคือตัวอย่างเทสต์ .wast:

;; Test `wasm:opcode:call` event

;; @instrument
(module
    ;; Auxiliary definitions
    (func $other (param i32) (result i32) (local.get 1))
    (func $dummy (param i32) (result i32) (local.get 0))

    ;; Test case functions
    (func (export "instrument_me") (result i32)
        (call $dummy (i32.const 0))
    )
)

;; WHAMM --> wasm:opcode:call:before { arg0 = 1; }
(assert_return (invoke "instrument_me") (i32.const 1)) ;; will be run with the above WHAMM instrumentation

;; WHAMM --> wasm:opcode:call:alt { alt_call_by_name("other"); }
(assert_return (invoke "instrument_me") (i32.const 1)) ;; will be run with the above WHAMM instrumentation

ด้านล่างคือตัวอย่างเทสต์ .wast ที่ใช้การนำเข้า:

(module
    (func (export "dummy") (param i32) (result i32)
        local.get 0
    )
)

(register "test")

;; @instrument
(module
    ;; Imports
    (type (;0;) (func (param i32) (result i32)))
    (import "test" "dummy" (func $dummy (type 0)))

    ;; Globals
    (global $var (mut i32) (i32.const 0))

    ;; Global getters
    (func $get_global_var (result i32)
        (global.get $var)
    )

    ;; Test case functions
    (func $foo
        (call $dummy (i32.const 0))
        global.set $var
    )

    (start $foo)
    (export "foo" (func $foo))
    (export "get_global_var" (func $get_global_var))
    (memory (;0;) 1)
 )
 
;; WHAMM --> var count: i32; wasm:opcode:call:alt / arg0 == 0 / { count = 5; return 1; }
(assert_return (invoke "get_global_var") (i32.const 1)) ;; alt, so global should be return value
(assert_return (invoke "get_count") (i32.const 5))

มีธรรมเนียมปฏิบัติหลายอย่างที่ควรทำตามเมื่อเขียนเคสเทสต์ .wast สำหรับ whamm

  1. มี module ที่จะทำ instrumentation เพียงหนึ่งโมดูลต่อไฟล์ .wast
    • การตั้งค่าเทสต์อยู่ด้านบน (ซึ่งรวมหลายโมดูลได้เมื่อพิจารณาการทดสอบการนำเข้า)
    • module ที่จะทำ instrumentation เป็นส่วนสุดท้ายของการตั้งค่า และมีเครื่องหมาย ;; @instrument กำกับเหนือโมดูล
  2. ใช้คอมเมนต์ระบุสคริปต์ Whamm ไวยากรณ์: ;; WHAMM --> <whamm_script>
    • สคริปต์ถูกรันบน module ในไฟล์ .wast
    • ถ้ามี asserts หลายอันใต้คอมเมนต์ Whamm อันหนึ่ง พวกมันทั้งหมดจะถูกรันกับ module ที่ทำ instrumentation แล้วซึ่งได้จากสคริปต์ Whamm นั้น
  3. แอสเซิร์ตทั้งหมดควร ล้มเหลว หากถูกรันโดยไม่มีการทำ instrumentation

หมายเหตุ: สำหรับ wei อย่าทำการปรับเปลี่ยนที่เปลี่ยน arg* (ซึ่งต้องใช้ตัวเข้าถึงเฟรม) ให้เปลี่ยนสถานะโกลบอลแทนไปก่อน?

โค้ดของฮาร์เนส

ฮาร์เนสอยู่ใน tests/common/wast_harness.rs โดยมีฟังก์ชัน main เป็นจุดเข้า เราเรียกฮาร์เนสนี้ผ่านการเรียกจุดเข้า main ในเคสเทสต์ run_wast_tests ที่อยู่ใน tests/integration_test.rs

ใครก็อ่านโค้ดของฮาร์เนสได้ และจะเห็นว่ามันทำตรรกะต่อไปนี้:

  1. แยกส่วนประกอบของเทสต์ จากแต่ละไฟล์ .wast ที่พบใต้ tests/wast_suite เป็น WastTestCase แต่ละรายการ
    • โมดูล wasm
    • สคริปต์ whamm
    • รายการแอสเซอร์ชันที่ควรเป็นจริงหลังทำ instrumentation
  2. ยืนยันว่าแอสเซอร์ชันทั้งหมดล้มเหลวก่อนทำ instrumentation ด้วย whamm เราทำเช่นนี้เพื่อยืนยันได้ว่าความถูกต้องของ instrumentation เป็นเหตุผลเดียวที่ทำให้เทสต์บางตัวผ่าน เรายืนยันคุณสมบัตินี้โดยสร้างไฟล์ .wast ใหม่ที่มีแอสเซอร์ชันเดียวต่อไฟล์ก่อน แล้วตรวจว่ามันล้มเหลวเมื่อรันบนอินเทอร์พรีเตอร์ที่รองรับ
    • เราสร้างไฟล์ .wast ใหม่แบบนี้เพราะอินเทอร์พรีเตอร์ที่เราใช้จะออกเมื่อเจอแอสเซอร์ชันแรกที่ล้มเหลวต่อไฟล์ .wast แต่เราต้องการรับประกันคุณสมบัตินี้กับทุกแอสเซอร์ชัน
  3. ยืนยันว่าแอสเซอร์ชันทั้งหมดผ่านหลังทำ instrumentation ด้วย whamm
    • รันสคริปต์ whamm ที่ระบุบนโมดูลต่อชุดแอสเซอร์ชัน
    • ส่งออกไฟล์ .wast ใหม่ที่มีโมดูลที่ทำ instrumentation แล้วพร้อมแอสเซอร์ชันที่เกี่ยวข้อง

อินเทอร์พรีเตอร์ที่รองรับ

ฮาร์เนสสร้างไฟล์ *.bin.wast เพื่อรันบนรายการเอนจิน เช่น wizeng และ spec interpreter

ดู README.md ของรีโพสำหรับวิธีตั้งค่าอินเทอร์พรีเตอร์ให้รันกับฮาร์เนสทดสอบของเรา

ไอเดียสำหรับการปรับปรุงในอนาคต

ตัวแปร Report

;; Use something like below to assert on the values of some report variable dynamically.
;; REPORT_TRACE(ID) --> 1, 3, 5, 6, 7

;; Use something like below to assert on report variable values!
;; WITH_WHAMM --> (assert_return (invoke "get_report_var" (i32.const 1)) (i32.const 7))