name: Test

on:
  pull_request:
  push:
    branches:
      - main
  workflow_dispatch:

env:
  CARGO_TERM_COLOR: always

jobs:
  format:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install formatting dependencies
        run: |
          sudo apt update
          sudo apt install gettext yapf3

      - name: Install nightly rustfmt
        run: |
          rustup default nightly
          rustup component add rustfmt

      - name: Check formatting
        uses: dprint/check@v2.3

  typos:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Check for typos
        uses: crate-ci/typos@v1.34.0
        with:
          config: ./.github/typos.toml

  cargo:
    strategy:
      matrix:
        os:
          - ubuntu-latest
          - macos-latest
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Update Rust
        run: rustup update

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache

      - name: Build Rust code
        run: cargo build

      - name: Test Rust code
        run: cargo test

  bare-metal:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        include:
          - directory: src/bare-metal/alloc-example
            target: aarch64-unknown-none
          - directory: src/bare-metal/aps/examples
            target: aarch64-unknown-none
          - directory: src/bare-metal/microcontrollers/examples
            target: thumbv7em-none-eabihf
          - directory: src/exercises/bare-metal/compass
            target: thumbv7em-none-eabihf
          - directory: src/exercises/bare-metal/rtc
            target: aarch64-unknown-none
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install toolchain
        run: |
          rustup update
          rustup target add ${{ matrix.target }}

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache

      - name: Install dependencies
        run: |
          sudo apt update
          sudo apt install gcc-aarch64-linux-gnu

      - name: Build Rust code
        working-directory: ${{ matrix.directory }}
        run: cargo build

  find-languages:
    runs-on: ubuntu-latest
    outputs:
      languages: ${{ steps.find-languages.outputs.languages }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Find languages
        id: find-languages
        shell: python
        run: |
          import os, json, pathlib
          languages = ["en"] + [p.stem for p in pathlib.Path("po").iterdir() if p.suffix == ".po"]
          github_output = open(os.environ["GITHUB_OUTPUT"], "a")
          github_output.write("languages=")
          json.dump(sorted(languages), github_output)

  build:
    runs-on: ubuntu-latest
    needs:
      - find-languages
    strategy:
      matrix:
        language: ${{ fromJSON(needs.find-languages.outputs.languages) }}
      fail-fast: false
    env:
      # Opt-in for checking links in translations - add the language below.
      LINK_CHECKED_LANGUAGES: '["en", "fa"]'
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # We need the full history for build.sh below.

      - name: Update Rust
        run: rustup update

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache
        with:
          key: ${{ contains(fromJSON(env.LINK_CHECKED_LANGUAGES), matrix.language) }}

      - name: Install Gettext
        run: |
          sudo apt update
          sudo apt install gettext

      - name: Install mdbook
        uses: ./.github/workflows/install-mdbook

      - name: Test format of ${{ matrix.language }} translation
        if: matrix.language != 'en'
        run: msgfmt --statistics -o /dev/null po/${{ matrix.language }}.po

      - name: Test extracting English strings
        if: matrix.language == 'en'
        run: |
          MDBOOK_OUTPUT='{"xgettext": {"pot-file": "messages.pot"}}' mdbook build -d po
          msgfmt -o /dev/null --statistics po/messages.pot

      - name: Build ${{ matrix.language }} translation
        run: |
          .github/workflows/build.sh ${{ matrix.language }} book/comprehensive-rust-${{ matrix.language }}

      # Upload the book now to retain it in case mdbook test fails.
      - name: Upload book
        uses: actions/upload-artifact@v4
        with:
          name: comprehensive-rust-${{ matrix.language }}
          path: book/

      - name: Test code snippets
        env:
          MDBOOK_BOOK__LANGUAGE: ${{ matrix.language }}
        run: mdbook test

      - name: Setup Node
        if: matrix.language == 'en'
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "npm"
          cache-dependency-path: "tests/package-lock.json"
      - name: Install test framework
        if: matrix.language == 'en'
        run: npm install
        working-directory: ./tests
      - name: Test Javascript
        if: matrix.language == 'en'
        run: |
          ./src/slides/create-slide.list.sh
          npm test
        env:
          TEST_BOOK_DIR: ../book/comprehensive-rust-${{ matrix.language }}/html
        working-directory: ./tests

  po-diff:
    name: Translation diff
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Update Rust
        run: rustup update

      - name: Setup Rust cache
        uses: ./.github/workflows/setup-rust-cache

      - name: Install mdbook
        uses: ./.github/workflows/install-mdbook

      - name: Copy latest version of translations
        run: cp -r po new-po

      - name: Checkout base version
        run: git checkout ${{ github.event.pull_request.base.sha }}

      - name: Translation diff
        run: i18n-report diff po/ new-po/ > $GITHUB_STEP_SUMMARY
