using System.Text; using System.Text.Json; using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; using DotNet.Testcontainers.Images; using MycroForge.CLI.Tests.Extensions; using MycroForge.Core; namespace MycroForge.CLI.Tests; public class InitCommandTests { private IFutureDockerImage Image = null!; private IContainer Container = null!; private async Task CreateImage() { Image = new ImageFromDockerfileBuilder() .WithDockerfileDirectory(CommonDirectoryPath.GetSolutionDirectory(), string.Empty) .WithDockerfile("Dockerfile") .WithCleanUp(true) .Build(); await Image.CreateAsync(); } private async Task CreateContainer() { Container = new ContainerBuilder() .WithImage(Image) .WithCleanUp(true) .Build(); await Container.StartAsync(); } [OneTimeSetUp] public async Task SetupOnce() { await CreateImage(); await CreateContainer(); await Container.ExecAsync(["m4g", "init", "todo"]); } [Test] public async Task Creates_m4g_json() { var bytes = await Container.ReadFileFromRootAsync("m4g.json"); using var stream = new MemoryStream(bytes); var config = await JsonSerializer.DeserializeAsync(stream, DefaultJsonSerializerOptions.Default); Assert.That(config, Is.Not.Null); Assert.Multiple(() => { Assert.That(config!.Api, Is.Not.Null); Assert.That(config.Api.Port, Is.EqualTo(8000)); Assert.That(config.Db, Is.Not.Null); Assert.That(config.Db.DbhPort, Is.EqualTo(5050)); Assert.That(config.Db.DbuPort, Is.EqualTo(5051)); }); } [Test] public async Task Creates_main_py() { var bytes = await Container.ReadFileFromRootAsync("main.py"); var text = Encoding.UTF8.GetString(bytes); var lines = text.Split('\n'); // TestContext.WriteLine(text); Assert.Multiple(() => { Assert.That(text, Is.Not.Empty); Assert.That(lines, Does.Contain("from fastapi import FastAPI")); Assert.That(lines, Does.Contain("from api.routers import hello")); Assert.That(lines, Does.Contain("app = FastAPI()")); Assert.That(lines, Does.Contain("app.include_router(prefix=\"/hello\", router=hello.router)")); }); } [Test] public async Task Creates_gitignore() { var bytes = await Container.ReadFileFromRootAsync(".gitignore"); var text = Encoding.UTF8.GetString(bytes); var lines = text.Split('\n'); // TestContext.WriteLine(text); Assert.Multiple(() => { Assert.That(text, Is.Not.Empty); Assert.That(lines, Does.Contain(".venv")); Assert.That(lines, Does.Contain("__pycache__/")); }); } [Test] public async Task Creates_alembic_ini() { var bytes = await Container.ReadFileFromRootAsync("alembic.ini"); var text = Encoding.UTF8.GetString(bytes); var lines = text.Split('\n'); // TestContext.WriteLine(text); Assert.Multiple(() => { Assert.That(text, Is.Not.Empty); Assert.That(lines, Does.Contain("[alembic]")); Assert.That(lines, Does.Contain("sqlalchemy.url = driver://user:pass@localhost/dbname")); }); } [Test] public async Task Creates_db_docker_compose_yml() { var bytes = await Container.ReadFileFromRootAsync("db.docker-compose.yml"); var text = Encoding.UTF8.GetString(bytes); var lines = text.Split('\n'); // TestContext.WriteLine(text); Assert.Multiple(() => { Assert.That(text, Is.Not.Empty); Assert.That(lines, Does.Contain(" todo_mariadb:")); Assert.That(lines, Does.Contain(" container_name: 'todo_mariadb'")); Assert.That(lines, Does.Contain(" - '${DBH_PORT}:3306'")); Assert.That(lines, Does.Contain(" MYSQL_DATABASE: 'todo'")); Assert.That(lines, Does.Contain(" - 'todo_mariadb:/var/lib/mysql'")); Assert.That(lines, Does.Contain(" todo_phpmyadmin:")); Assert.That(lines, Does.Contain(" container_name: todo_phpmyadmin")); Assert.That(lines, Does.Contain(" PMA_HOST: todo_mariadb")); Assert.That(lines, Does.Contain(" - todo_mariadb")); Assert.That(lines, Does.Contain(" todo_mariadb:")); }); } [Test] public async Task Creates_api__router_hello_py() { var bytes = await Container.ReadFileFromRootAsync("api/routers/hello.py"); var text = Encoding.UTF8.GetString(bytes); var lines = text.Split('\n'); // TestContext.WriteLine(text); Assert.Multiple(() => { Assert.That(text, Is.Not.Empty); Assert.That(lines, Does.Contain("from fastapi import APIRouter")); Assert.That(lines, Does.Contain("from fastapi.responses import JSONResponse")); Assert.That(lines, Does.Contain("from fastapi.encoders import jsonable_encoder")); Assert.That(lines, Does.Contain("router = APIRouter()")); Assert.That(lines, Does.Contain("@router.get(\"/{name}\")")); Assert.That(lines, Does.Contain("async def hello(name: str):")); Assert.That(lines, Does.Contain("\treturn JSONResponse(status_code=200, content=jsonable_encoder({'greeting': f\"Hello, {name}!\"}))")); }); } [Test] public async Task Creates_db__engine__async_session_py() { var bytes = await Container.ReadFileFromRootAsync("db/engine/async_session.py"); var text = Encoding.UTF8.GetString(bytes); var lines = text.Split('\n'); // TestContext.WriteLine(text); Assert.Multiple(() => { Assert.That(text, Is.Not.Empty); Assert.That(lines, Does.Contain("from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine, AsyncSession")); Assert.That(lines, Does.Contain("from db.settings import DbSettings")); Assert.That(lines, Does.Contain("async_engine: AsyncEngine = create_async_engine(DbSettings.get_connectionstring())")); Assert.That(lines, Does.Contain("def async_session() -> AsyncSession:")); Assert.That(lines, Does.Contain("\treturn AsyncSession(async_engine, expire_on_commit=False)")); }); } [Test] public async Task Creates_db__entities__entity_base_py() { var bytes = await Container.ReadFileFromRootAsync("db/entities/entity_base.py"); var text = Encoding.UTF8.GetString(bytes); var lines = text.Split('\n'); // TestContext.WriteLine(text); Assert.Multiple(() => { Assert.That(text, Is.Not.Empty); Assert.That(lines, Does.Contain("from sqlalchemy.orm import DeclarativeBase")); Assert.That(lines, Does.Contain("class EntityBase(DeclarativeBase):")); Assert.That(lines, Does.Contain("\tpass")); }); } [Test] public async Task Creates_db__settings_py() { var bytes = await Container.ReadFileFromRootAsync("db/settings.py"); var text = Encoding.UTF8.GetString(bytes); var lines = text.Split('\n'); // TestContext.WriteLine(text); Assert.Multiple(() => { Assert.That(text, Is.Not.Empty); Assert.That(lines, Does.Contain("class DbSettings:")); Assert.That(lines, Does.Contain("\tdef get_connectionstring() -> str:")); Assert.That(lines, Does.Contain("\t\tconnectionstring = \"mysql+asyncmy://root:password@localhost:5050/todo\"")); Assert.That(lines, Does.Contain("\t\treturn connectionstring")); }); } }