Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

breaking test(test_man_code.py); yet to be modified #176

Merged
merged 6 commits into from
Jan 28, 2024
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
14 changes: 2 additions & 12 deletions jaclang/cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"""Command line interface tool for the Jac language."""
import os
import shutil
import unittest
from typing import Optional

from jaclang import jac_import as __jac_import__
from jaclang.cli.cmdreg import CommandRegistry, CommandShell
from jaclang.compiler.constant import Constants
from jaclang.compiler.passes.tool.schedules import format_pass
from jaclang.compiler.transpiler import jac_file_to_pass
from jaclang.plugin.feature import JacFeature as Jac
from jaclang.utils.lang_tools import AstTool


Expand Down Expand Up @@ -84,17 +84,7 @@ def test(filename: str) -> None:

:param filename: The path to the .jac file.
"""
if filename.endswith(".jac"):
base, mod_name = os.path.split(filename)
base = base if base else "./"
mod_name = mod_name[:-4]
mod = __jac_import__(target=mod_name, base_path=base)
if hasattr(mod, "__jac_suite__"):
unittest.TextTestRunner().run(getattr(mod, "__jac_suite__")) # noqa: B009
else:
print("No tests found.")
else:
print("Not a .jac file.")
Jac.run_test(filename)


@cmd_registry.register
Expand Down
41 changes: 13 additions & 28 deletions jaclang/compiler/passes/main/pyast_gen_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,21 +113,6 @@ def needs_jac_feature(self) -> None:
)
self.already_added.append("jac_feature")

def needs_test(self) -> None:
"""Check if test is needed."""
if "test" in self.already_added:
return
test_code = (
"import unittest as __jac_unittest__\n"
"__jac_tc__ = __jac_unittest__.TestCase()\n"
"__jac_suite__ = __jac_unittest__.TestSuite()\n"
"class __jac_check:\n"
" def __getattr__(self, name):\n"
" return getattr(__jac_tc__, 'assert'+name)"
)
self.preamble += ast3.parse(test_code).body
self.already_added.append("test")

def flatten(self, body: list[T | list[T] | None]) -> list[T]:
"""Flatten ast list."""
new_body = []
Expand Down Expand Up @@ -279,15 +264,14 @@ def exit_test(self, node: ast.Test) -> None:
body: SubNodeList[CodeBlockStmt],
doc: Optional[String],
"""
self.needs_test()
test_name = node.name.sym_name
func = self.sync(
ast3.FunctionDef(
name=test_name,
args=self.sync(
ast3.arguments(
posonlyargs=[],
args=[],
args=[self.sync(ast3.arg(arg="check", annotation=None))],
kwonlyargs=[],
vararg=None,
kwargs=None,
Expand All @@ -296,22 +280,23 @@ def exit_test(self, node: ast.Test) -> None:
)
),
body=self.resolve_stmt_block(node.body, doc=node.doc),
decorator_list=[],
decorator_list=[
self.sync(
ast3.Attribute(
value=self.sync(
ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
),
attr="create_test",
ctx=ast3.Load(),
)
)
],
returns=self.sync(ast3.Constant(value=None)),
type_comment=None,
type_params=[],
),
)
func.body.insert(
0,
self.sync(ast3.parse("check = __jac_check()").body[0]),
)
check = self.sync(
ast3.parse(
f"__jac_suite__.addTest(__jac_unittest__.FunctionTestCase({test_name}))"
).body[0]
)
node.gen.py_ast = [func, check]
node.gen.py_ast = func

def exit_module_code(self, node: ast.ModuleCode) -> None:
"""Sub objects.
Expand Down
30 changes: 29 additions & 1 deletion jaclang/core/construct.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
from __future__ import annotations

import types
import unittest
from dataclasses import dataclass, field
from typing import Any, Callable, Optional
from typing import Any, Callable, Optional, Union


from jaclang.compiler.constant import EdgeDir
Expand Down Expand Up @@ -299,4 +300,31 @@ def resolve(self, cls: type) -> None:
self.func = getattr(cls, self.name)


class JacTestCheck:
"""Jac Testing and Checking."""

test_case = unittest.TestCase()
test_suite = unittest.TestSuite()

@staticmethod
def reset() -> None:
"""Clear the test suite."""
JacTestCheck.test_case = unittest.TestCase()
JacTestCheck.test_suite = unittest.TestSuite()

@staticmethod
def run_test() -> None:
"""Run the test suite."""
unittest.TextTestRunner().run(JacTestCheck.test_suite)

@staticmethod
def add_test(test_fun: Callable) -> None:
"""Create a new test."""
JacTestCheck.test_suite.addTest(unittest.FunctionTestCase(test_fun))

def __getattr__(self, name: str) -> Union[bool, Any]:
"""Make convenient check.Equal(...) etc."""
return getattr(JacTestCheck.test_case, "assert" + name)


root = Root()
34 changes: 33 additions & 1 deletion jaclang/plugin/default.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
"""Jac Language Features."""
from __future__ import annotations

import os
from dataclasses import dataclass, field
from functools import wraps
from typing import Any, Callable, Optional, Type


from jaclang import jac_import
from jaclang.plugin.spec import (
ArchBound,
Architype,
Expand All @@ -14,6 +15,7 @@
EdgeArchitype,
EdgeDir,
GenericEdge,
JacTestCheck,
NodeArchitype,
T,
WalkerArchitype,
Expand Down Expand Up @@ -69,6 +71,36 @@ def new_init(self: ArchBound, *args: object, **kwargs: object) -> None:

return decorator

@staticmethod
@hookimpl
def create_test(test_fun: Callable) -> Callable:
"""Create a new test."""

def test_deco() -> None:
test_fun(JacTestCheck())

test_deco.__name__ = test_fun.__name__
JacTestCheck.add_test(test_deco)

return test_deco

@staticmethod
@hookimpl
def run_test(filename: str) -> None:
"""Run the test suite in the specified .jac file.

:param filename: The path to the .jac file.
"""
if filename.endswith(".jac"):
base, mod_name = os.path.split(filename)
base = base if base else "./"
mod_name = mod_name[:-4]
JacTestCheck.reset()
jac_import(target=mod_name, base_path=base)
JacTestCheck.run_test()
else:
print("Not a .jac file.")

@staticmethod
@hookimpl
def elvis(op1: Optional[T], op2: T) -> T:
Expand Down
10 changes: 10 additions & 0 deletions jaclang/plugin/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ def make_architype(
arch_type=arch_type, on_entry=on_entry, on_exit=on_exit
)

@staticmethod
def create_test(test_fun: Callable) -> Callable:
"""Create a test."""
return JacFeature.pm.hook.create_test(test_fun=test_fun)

@staticmethod
def run_test(filename: str) -> None:
"""Run the test suite in the specified .jac file."""
return JacFeature.pm.hook.run_test(filename=filename)

@staticmethod
def elvis(op1: Optional[T], op2: T) -> T:
"""Jac's elvis operator feature."""
Expand Down
17 changes: 17 additions & 0 deletions jaclang/plugin/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
EdgeArchitype,
EdgeDir,
GenericEdge,
JacTestCheck,
NodeAnchor,
NodeArchitype,
ObjectAnchor,
Expand All @@ -23,6 +24,7 @@
__all__ = [
"EdgeAnchor",
"GenericEdge",
"JacTestCheck",
"NodeAnchor",
"ObjectAnchor",
"WalkerAnchor",
Expand Down Expand Up @@ -56,6 +58,21 @@ def make_architype(
"""Create a new architype."""
raise NotImplementedError

@staticmethod
@hookspec(firstresult=True)
def create_test(test_fun: Callable) -> Callable:
"""Create a new test."""
raise NotImplementedError

@staticmethod
@hookspec(firstresult=True)
def run_test(filename: str) -> None:
"""Run the test suite in the specified .jac file.

:param filename: The path to the .jac file.
"""
raise NotImplementedError

@staticmethod
@hookspec(firstresult=True)
def elvis(op1: Optional[T], op2: T) -> T:
Expand Down
Loading