Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Lint and Test

on:
pull_request:
push:
branches: [dev]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.10"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install .
pip install flake8 pylint

- run: flake8 nasal_api_docs --config setup.cfg
- run: pylint --rcfile setup.cfg nasal_api_docs
- run: pytest
18 changes: 18 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Module",
"type": "debugpy",
"request": "launch",
"module": "nasal_api_docs",
"args": [
"-f",
"FGROOT/FGDATA"
]
}
]
}
37 changes: 37 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "View output in a local http server",
"type": "shell",
"problemMatcher": [],
"command": "${command:python.interpreterPath}",
"args": [
"-m",
"http.server",
"8000",
"-d",
"out",
"-b",
"127.0.0.1"
]
},
{
"label": "Test package",
"type": "shell",
"problemMatcher": [],
"command": "${command:python.interpreterPath}",
"args": [
"-m",
"pytest",
"--basetemp=tmp"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
2 changes: 1 addition & 1 deletion nasal_api_docs/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from platform import python_version as pl_python_version

from jinja2 import Environment, FileSystemLoader, select_autoescape
from . import __version__
from . import __version__ # pylint: disable=cyclic-import
from .filesystem import NasalFileSystem
from .parser import NasalParser

Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ build-backend = "setuptools.build_meta"
name = "nasal-api-docs"
version = "0.2.0"
dependencies = [
"Jinja2>=3.1.6,<4.0.0"
"Jinja2>=3.1.6,<4",
"pytest>=8.4.2,<9"
]
requires-python = ">=3.7"
authors = [
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ max-line-length = 88

[pylint]
max-line-length = 88
disable = too-few-public-methods, too-many-instance-attributes
Empty file added tests/__init__.py
Empty file.
86 changes: 86 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Copyright (C) 2012 Adrian Musceac
# Copyright (C) 2019-2026 RenanMsV
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Shared pytest configuration and fixtures for nasal_api_docs tests."""

from pathlib import Path
import pytest

from nasal_api_docs import NasalAPI


@pytest.fixture(scope="session")
def fg_root_dir(tmp_path_factory: pytest.TempPathFactory) -> Path:
"""
Provides a temporary fake FlightGear root directory with the minimal structure
required by tests.

The layout will be:
tmp/
├── fgdata/
│ └── Nasal/
└── output/

Returns:
Path: The path to the created fgdata directory (used as fg_root_dir).
"""
tmp_root = tmp_path_factory.mktemp("tmp")

# Create folder structure
fg_dir = tmp_root / "fgdata"
nasal_dir = fg_dir / "Nasal"

fg_dir.mkdir(parents=True, exist_ok=True)
nasal_dir.mkdir(parents=True, exist_ok=True)

# Create a fake FlightGear version file
(fg_dir / "version").write_text("9797.1.0", encoding="utf-8")

# Create a small fake .nas file
(nasal_dir / "aircraft.nas").write_text(
"# This is a comment first line\n"
"# \n"
"# This is a comment third line\n"
"#\n"
"var makeNode = func(n, anotherArgument) {\n"
"\tif (isa(n, props.Node))\n"
"\t\treturn n;\n"
"\telse\n"
"\t\treturn props.globals.getNode(n, 1);\n"
"}\n",
encoding="utf-8",
)

return fg_dir


@pytest.fixture(scope="session")
def output_dir(tmp_path_factory: pytest.TempPathFactory) -> Path:
"""
Provides a temporary output directory for generated documentation.

Returns:
Path: The path to the created temporary output directory.
"""
# Let pytest handle temp directory creation and cleanup
out_dir = tmp_path_factory.mktemp("output")
return out_dir


@pytest.fixture(scope="session")
def nasal_api(fg_root_dir: Path, output_dir: Path) -> NasalAPI: # pylint: disable=W0621
"""Provides a ready-to-use NasalAPI instance for all tests."""
return NasalAPI(fg_root_dir=fg_root_dir, output_dir=output_dir)
24 changes: 24 additions & 0 deletions tests/core_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (C) 2012 Adrian Musceac
# Copyright (C) 2019-2026 RenanMsV
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Core integration tests for the nasal_api_docs package."""

from nasal_api_docs import NasalAPI


def test_importable():
"""Ensure the main class NasalAPI can be imported."""
assert NasalAPI is not None
98 changes: 98 additions & 0 deletions tests/generator_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Copyright (C) 2012 Adrian Musceac
# Copyright (C) 2019-2026 RenanMsV
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""HTML generator tests for the nasal_api_docs package."""

import json
from nasal_api_docs import NasalAPI, parser


def test_basic_generation(nasal_api: NasalAPI):
"""Test that the API can read fg_version and generate documentation."""
version = nasal_api.get_fg_version()
assert version.startswith("9797"), "Incorrect or missing FG version"

html_path = nasal_api.generate_html()
json_path = nasal_api.generate_json_tree()

assert html_path.exists(), "HTML output file not created"
assert json_path.exists(), "JSON output file not created"


def test_html_generation(nasal_api: NasalAPI):
"""Test that the API generated a reasonable enough html."""
html_path = nasal_api.generate_html()

assert html_path.exists(), "HTML output file not created"

with open(html_path, "r", encoding="utf-8") as file:
data = file.read()

assert "<title>Nasal API - 9797.1.0</title>" in data, "Incorrect title."

assert "FlightGear version: 9797.1.0 .<br/>" in data, "Incorrect FG version."

assert (
"<a target=\"_blank\" href=\""
"http://plausible.org/nasal\">Plausible.org</a>"
) in data, "Missing link buttons."

assert (
"<a class=\"main_module_link\" href="
"\"#aircraft.nas\">&#128196; aircraft</a>"
) in data, "Incorrect module link in right namespace menu."

assert (
"<a name=\"aircraft.nas\">&#128196; aircraft</a>"
) in data, "Incorrect namespace title."

assert (
"<span class=\"rel_path\">&nbsp;&nbsp;&nbsp;&nbsp;"
"Nasal/aircraft.nas</span>"
) in data, "Incorrect path of Nasal file."

assert (
"<b>aircraft</b>.<b>makeNode</b> ( <span class=\"arg\">n</span>, "
"<span class=\"arg\">anotherArgument</span> )"
) in data, "Incorrect function name and parameters."

assert (
"<div class=\"comments\">This is a comment first line</div><br/>"
) in data, "Incorrect comment."

assert (
"<div class=\"comments\">This is a comment third line</div><br/>"
) in data, "Incorrect comment."


def test_json_generation(nasal_api: NasalAPI):
"""Test that the API generated a reasonable enough json."""
json_path = nasal_api.generate_json_tree()

assert json_path.exists(), "JSON output file not created"

with open(json_path, "r", encoding="utf-8") as file:
data = json.load(file)

assert data["meta"], "Missing metadata"

assert data["meta"]["fg_version"].startswith("9797"), (
"Incorrect or missing FG version."
)

assert data["meta"]["parser_version"] == parser.NasalParser.VERSION_STR, (
"Incorrect parser version."
)
Loading