Skip to content
Open
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
106 changes: 106 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: tests
on:
push:
branches: [master]
pull_request:

env:
# setup-python@v5 and setup-go@v5 don't have Node.js 24 releases yet
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
python-tests:
name: Python tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]

steps:
- uses: actions/checkout@v5

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: "22"

- name: Install Python dependencies
working-directory: libs/openant-core
run: pip install -r requirements.txt && pip install pytest

- name: Install JS parser dependencies
working-directory: libs/openant-core/parsers/javascript
run: npm install

- name: Run Python and parser tests
working-directory: libs/openant-core
run: python -m pytest tests/test_token_tracker.py tests/test_parser_adapter.py tests/test_python_parser.py tests/test_js_parser.py -v

go-tests:
name: Go build + integration (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]

steps:
- uses: actions/checkout@v5

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: apps/openant-cli/go.mod
cache-dependency-path: apps/openant-cli/go.sum

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: "22"

- name: Vet
working-directory: apps/openant-cli
run: go vet ./...

- name: Build (Linux/macOS)
if: runner.os != 'Windows'
working-directory: apps/openant-cli
run: go build -o openant .

- name: Build (Windows)
if: runner.os == 'Windows'
working-directory: apps/openant-cli
run: go build -o openant.exe .

- name: Verify binary exists
working-directory: apps/openant-cli
shell: bash
run: |
if [ -f openant ] || [ -f openant.exe ]; then
echo "Binary built successfully"
else
echo "ERROR: Binary not found" && exit 1
fi

- name: Install Python dependencies
working-directory: libs/openant-core
run: pip install -r requirements.txt && pip install pytest

- name: Install JS parser dependencies
working-directory: libs/openant-core/parsers/javascript
run: npm install

- name: Run Go CLI integration tests
working-directory: libs/openant-core
run: python -m pytest tests/test_go_cli.py -v --tb=short
3 changes: 3 additions & 0 deletions libs/openant-core/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[pytest]
testpaths = tests
pythonpath = .
Empty file.
32 changes: 32 additions & 0 deletions libs/openant-core/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Shared fixtures for OpenAnt tests."""
import sys
from pathlib import Path

import pytest

# Ensure the project root is on sys.path so imports like `from utilities...` work
PROJECT_ROOT = Path(__file__).parent.parent
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))

FIXTURES_DIR = Path(__file__).parent / "fixtures"
SAMPLE_PYTHON_REPO = FIXTURES_DIR / "sample_python_repo"
SAMPLE_JS_REPO = FIXTURES_DIR / "sample_js_repo"


@pytest.fixture
def sample_python_repo():
"""Path to the sample Python repository fixture."""
return str(SAMPLE_PYTHON_REPO)


@pytest.fixture
def sample_js_repo():
"""Path to the sample JavaScript repository fixture."""
return str(SAMPLE_JS_REPO)


@pytest.fixture
def tmp_output_dir(tmp_path):
"""Temporary output directory for parser results."""
return str(tmp_path / "output")
24 changes: 24 additions & 0 deletions libs/openant-core/tests/fixtures/sample_js_repo/src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const express = require("express");
const { getUser, createUser } = require("./db");

const app = express();
app.use(express.json());

app.get("/users/:id", async (req, res) => {
const user = await getUser(req.params.id);
if (!user) {
return res.status(404).json({ error: "Not found" });
}
res.json(user);
});

app.post("/users", async (req, res) => {
const { name } = req.body;
if (!name) {
return res.status(400).json({ error: "Name required" });
}
const user = await createUser(name);
res.status(201).json(user);
});

module.exports = app;
29 changes: 29 additions & 0 deletions libs/openant-core/tests/fixtures/sample_js_repo/src/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const sqlite3 = require("sqlite3");

function getConnection() {
return new sqlite3.Database("app.db");
}

async function getUser(id) {
const db = getConnection();
return new Promise((resolve, reject) => {
db.get("SELECT * FROM users WHERE id = ?", [id], (err, row) => {
db.close();
if (err) reject(err);
else resolve(row || null);
});
});
}

async function createUser(name) {
const db = getConnection();
return new Promise((resolve, reject) => {
db.run("INSERT INTO users (name) VALUES (?)", [name], function (err) {
db.close();
if (err) reject(err);
else resolve({ id: this.lastID, name });
});
});
}

module.exports = { getUser, createUser, getConnection };
12 changes: 12 additions & 0 deletions libs/openant-core/tests/fixtures/sample_js_repo/src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function sanitizeInput(value) {
if (typeof value !== "string") {
return String(value);
}
return value.trim();
}

function validateEmail(email) {
return email.includes("@") && email.includes(".");
}

module.exports = { sanitizeInput, validateEmail };
23 changes: 23 additions & 0 deletions libs/openant-core/tests/fixtures/sample_python_repo/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Sample Flask app for testing."""
from flask import Flask, request, jsonify
from .db import get_user, create_user

app = Flask(__name__)


@app.route("/users/<int:user_id>")
def get_user_endpoint(user_id):
user = get_user(user_id)
if not user:
return jsonify({"error": "Not found"}), 404
return jsonify(user)


@app.route("/users", methods=["POST"])
def create_user_endpoint():
data = request.get_json()
name = data.get("name")
if not name:
return jsonify({"error": "Name required"}), 400
user = create_user(name)
return jsonify(user), 201
25 changes: 25 additions & 0 deletions libs/openant-core/tests/fixtures/sample_python_repo/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Sample database module for testing."""
import sqlite3


def get_connection():
return sqlite3.connect("app.db")


def get_user(user_id):
conn = get_connection()
cursor = conn.execute("SELECT * FROM users WHERE id = ?", (user_id,))
row = cursor.fetchone()
conn.close()
if row:
return {"id": row[0], "name": row[1]}
return None


def create_user(name):
conn = get_connection()
cursor = conn.execute("INSERT INTO users (name) VALUES (?)", (name,))
conn.commit()
user_id = cursor.lastrowid
conn.close()
return {"id": user_id, "name": name}
11 changes: 11 additions & 0 deletions libs/openant-core/tests/fixtures/sample_python_repo/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Sample utility module for testing."""


def sanitize_input(value):
if not isinstance(value, str):
return str(value)
return value.strip()


def validate_email(email):
return "@" in email and "." in email
Loading