這是關於使用 Rust 和 WebAssembly 的未發佈文件,已發佈的文件可在Rust 和 WebAssembly 文件主網站上找到。這裡記錄的功能可能在 Rust 和 WebAssembly 工具的已發佈版本中不可用。

測試康威的生命遊戲

現在我們已經使用 JavaScript 在瀏覽器中呈現了生命遊戲的 Rust 實作,讓我們來談談如何測試我們用 Rust 生成的 WebAssembly 函數。

我們將測試我們的 tick 函數,以確保它能提供我們預期的輸出。

接下來,我們要在 wasm_game_of_life/src/lib.rs 文件中現有的 impl Universe 區塊內建立一些設置器和獲取器函數。我們將建立 set_widthset_height 函數,以便建立不同大小的 Universe


# #![allow(unused_variables)]
#fn main() {
#[wasm_bindgen]
impl Universe { 
    // ...

    /// Set the width of the universe.
    ///
    /// Resets all cells to the dead state.
    pub fn set_width(&mut self, width: u32) {
        self.width = width;
        self.cells = (0..width * self.height).map(|_i| Cell::Dead).collect();
    }

    /// Set the height of the universe.
    ///
    /// Resets all cells to the dead state.
    pub fn set_height(&mut self, height: u32) {
        self.height = height;
        self.cells = (0..self.width * height).map(|_i| Cell::Dead).collect();
    }

}
#}

我們將在 wasm_game_of_life/src/lib.rs 文件中建立另一個沒有 #[wasm_bindgen] 屬性的 impl Universe 區塊。我們需要一些用於測試的函數,這些函數不希望暴露給我們的 JavaScript。Rust 生成的 WebAssembly 函數無法返回借用的引用。嘗試使用該屬性編譯 Rust 生成的 WebAssembly,並查看您收到的錯誤訊息。

我們將編寫 get_cells 的實作,以獲取 Universecells 的內容。我們還將編寫一個 set_cells 函數,以便我們可以將 Universe 中特定行和列的 cells 設置為 Alive


# #![allow(unused_variables)]
#fn main() {
impl Universe {
    /// Get the dead and alive values of the entire universe.
    pub fn get_cells(&self) -> &[Cell] {
        &self.cells
    }

    /// Set cells to be alive in a universe by passing the row and column
    /// of each cell as an array.
    pub fn set_cells(&mut self, cells: &[(u32, u32)]) {
        for (row, col) in cells.iter().cloned() {
            let idx = self.get_index(row, col);
            self.cells[idx] = Cell::Alive;
        }
    }

}
#}

現在我們將在 wasm_game_of_life/tests/web.rs 文件中建立測試。

在此之前,該文件中已經有一個可用的測試。您可以通過在 wasm-game-of-life 目錄中運行 wasm-pack test --chrome --headless 來確認 Rust 生成的 WebAssembly 測試是否正常。您也可以使用 --firefox--safari--node 選項在這些瀏覽器中測試您的程式碼。

wasm_game_of_life/tests/web.rs 文件中,我們需要匯出我們的 wasm_game_of_life crate 和 Universe 類型。


# #![allow(unused_variables)]
#fn main() {
extern crate wasm_game_of_life;
use wasm_game_of_life::Universe;
#}

wasm_game_of_life/tests/web.rs 文件中,我們要建立一些太空船構建器函數。

我們需要一個用於輸入太空船的函數,我們將在該函數上調用 tick 函數,並且我們需要在一次 tick 後獲得的預期太空船。我們在 input_spaceship 函數中選擇了要初始化為 Alive 的單元格來建立我們的太空船。在 expected_spaceship 函數中,輸入太空船在 tick 後的位置是手動計算的。您可以自行確認輸入太空船在一次 tick 後的單元格與預期太空船相同。


# #![allow(unused_variables)]
#fn main() {
#[cfg(test)]
pub fn input_spaceship() -> Universe {
    let mut universe = Universe::new();
    universe.set_width(6);
    universe.set_height(6);
    universe.set_cells(&[(1,2), (2,3), (3,1), (3,2), (3,3)]);
    universe
}

#[cfg(test)]
pub fn expected_spaceship() -> Universe {
    let mut universe = Universe::new();
    universe.set_width(6);
    universe.set_height(6);
    universe.set_cells(&[(2,1), (2,3), (3,2), (3,3), (4,2)]);
    universe
}
#}

現在我們將編寫 test_tick 函數的實作。首先,我們建立 input_spaceship()expected_spaceship() 的實例。然後,我們在 input_universe 上調用 tick。最後,我們使用 assert_eq! 巨集來調用 get_cells(),以確保 input_universeexpected_universe 具有相同的 Cell 陣列值。我們在程式碼區塊中添加 #[wasm_bindgen_test] 屬性,以便我們可以測試 Rust 生成的 WebAssembly 程式碼,並使用 wasm-pack test 來測試 WebAssembly 程式碼。


# #![allow(unused_variables)]
#fn main() {
#[wasm_bindgen_test]
pub fn test_tick() {
    // Let's create a smaller Universe with a small spaceship to test!
    let mut input_universe = input_spaceship();

    // This is what our spaceship should look like
    // after one tick in our universe.
    let expected_universe = expected_spaceship();

    // Call `tick` and then see if the cells in the `Universe`s are the same.
    input_universe.tick();
    assert_eq!(&input_universe.get_cells(), &expected_universe.get_cells());
}
#}

通過運行 wasm-pack test --firefox --headlesswasm-game-of-life 目錄中運行測試。