ฮาร์เนสทดสอบ .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
- มี
moduleที่จะทำ instrumentation เพียงหนึ่งโมดูลต่อไฟล์.wast- การตั้งค่าเทสต์อยู่ด้านบน (ซึ่งรวมหลายโมดูลได้เมื่อพิจารณาการทดสอบการนำเข้า)
moduleที่จะทำ instrumentation เป็นส่วนสุดท้ายของการตั้งค่า และมีเครื่องหมาย;; @instrumentกำกับเหนือโมดูล
- ใช้คอมเมนต์ระบุสคริปต์
Whammไวยากรณ์:;; WHAMM --> <whamm_script>- สคริปต์ถูกรันบน
moduleในไฟล์.wast - ถ้ามี
assertsหลายอันใต้คอมเมนต์Whammอันหนึ่ง พวกมันทั้งหมดจะถูกรันกับmoduleที่ทำ instrumentation แล้วซึ่งได้จากสคริปต์Whammนั้น
- สคริปต์ถูกรันบน
- แอสเซิร์ตทั้งหมดควร ล้มเหลว หากถูกรันโดยไม่มีการทำ instrumentation
หมายเหตุ: สำหรับ wei อย่าทำการปรับเปลี่ยนที่เปลี่ยน arg* (ซึ่งต้องใช้ตัวเข้าถึงเฟรม) ให้เปลี่ยนสถานะโกลบอลแทนไปก่อน?
โค้ดของฮาร์เนส
ฮาร์เนสอยู่ใน tests/common/wast_harness.rs โดยมีฟังก์ชัน main เป็นจุดเข้า
เราเรียกฮาร์เนสนี้ผ่านการเรียกจุดเข้า main ในเคสเทสต์ run_wast_tests ที่อยู่ใน tests/integration_test.rs
ใครก็อ่านโค้ดของฮาร์เนสได้ และจะเห็นว่ามันทำตรรกะต่อไปนี้:
- แยกส่วนประกอบของเทสต์ จากแต่ละไฟล์
.wastที่พบใต้tests/wast_suiteเป็นWastTestCaseแต่ละรายการ- โมดูล
wasm - สคริปต์
whamm - รายการแอสเซอร์ชันที่ควรเป็นจริงหลังทำ instrumentation
- โมดูล
- ยืนยันว่าแอสเซอร์ชันทั้งหมดล้มเหลวก่อนทำ instrumentation ด้วย
whammเราทำเช่นนี้เพื่อยืนยันได้ว่าความถูกต้องของ instrumentation เป็นเหตุผลเดียวที่ทำให้เทสต์บางตัวผ่าน เรายืนยันคุณสมบัตินี้โดยสร้างไฟล์.wastใหม่ที่มีแอสเซอร์ชันเดียวต่อไฟล์ก่อน แล้วตรวจว่ามันล้มเหลวเมื่อรันบนอินเทอร์พรีเตอร์ที่รองรับ- เราสร้างไฟล์
.wastใหม่แบบนี้เพราะอินเทอร์พรีเตอร์ที่เราใช้จะออกเมื่อเจอแอสเซอร์ชันแรกที่ล้มเหลวต่อไฟล์.wastแต่เราต้องการรับประกันคุณสมบัตินี้กับทุกแอสเซอร์ชัน
- เราสร้างไฟล์
- ยืนยันว่าแอสเซอร์ชันทั้งหมดผ่านหลังทำ 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))