Skip to content

Commit

Permalink
add invalid data test
Browse files Browse the repository at this point in the history
  • Loading branch information
GoodenoughPhysicsLab committed Jan 1, 2025
1 parent 94bf2b2 commit 3567abc
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 60 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
jobs:
build:

runs-on: ${{ matrix.os }}
runs-on: test on ${{ matrix.os }} with ${{ matrix.python-version }}
strategy:
fail-fast: false
matrix:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ physicsLabSav/

# special file of physicsLab
*.sav
!test_pl/data/*.sav
*.mido.py
*.pl.py
*.test.*
Expand Down
124 changes: 80 additions & 44 deletions physicsLab/Experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ class Experiment:
else:
SAV_PATH_DIR = "physicsLabSav"

SAV_PATH: str # 存档的完整路径

@overload
def __init__(self, open_mode: OpenMode, sav_name: str) -> None:
''' 根据存档名打开存档
Expand Down Expand Up @@ -138,25 +136,21 @@ def __init__(self, open_mode: OpenMode, *args) -> None:

# 尽管读取存档时会将元件的字符串一并读入, 但只有在调用 load_elements 将元件的信息
# 导入self.Elements与self._element_position之后, 元件信息才被完全导入
if open_mode == OpenMode.load_by_sav_name or open_mode == OpenMode.load_by_filepath:
sav_name, *rest = args

if not isinstance(sav_name, str) or len(rest) != 0:
raise TypeError

if open_mode == OpenMode.load_by_sav_name or open_mode == OpenMode.load_by_filepath or open_mode == OpenMode.load_by_plar_app:
if open_mode == OpenMode.load_by_filepath:
sav_name, *rest = args
if not isinstance(sav_name, str) or len(rest) != 0:
raise TypeError

self.SAV_PATH = os.path.abspath(sav_name)

if not os.path.exists(self.SAV_PATH):
raise errors.ExperimentNotExistError(f"{self.SAV_PATH} not found")
raise FileNotFoundError(f"\"{self.SAV_PATH}\" not found")
if _ExperimentStack.inside(self):
raise errors.ExperimentOpenedError

_ExperimentStack.push(self)
_temp = _open_sav(self.SAV_PATH)

assert _temp is not None # ??? 万一就是用户的输入不对呢

if "Experiment" in _temp.keys():
self.PlSav = _temp
else: # 读取物实导出的存档只含有.sav的Experiment部分
Expand All @@ -170,7 +164,13 @@ def __init__(self, open_mode: OpenMode, *args) -> None:
raise errors.InternalError

self.PlSav["Experiment"] = _temp

_ExperimentStack.push(self)
elif open_mode == OpenMode.load_by_sav_name:
sav_name, *rest = args
if not isinstance(sav_name, str) or len(rest) != 0:
raise TypeError

filename = search_experiment(sav_name)
if filename is None:
raise errors.ExperimentNotExistError(f'No such experiment "{sav_name}"')
Expand All @@ -179,9 +179,47 @@ def __init__(self, open_mode: OpenMode, *args) -> None:
if _ExperimentStack.inside(self):
raise errors.ExperimentOpenedError

_ExperimentStack.push(self)
_ExperimentStack.push(self) # TODO 所有的_Experiment.push都应该在构造函数快完成的时候才执行

self.PlSav = search_experiment.sav
elif open_mode == OpenMode.load_by_plar_app:
content_id, category, *rest = args

if not isinstance(content_id, str) or not isinstance(category, Category):
raise TypeError
if len(rest) == 0:
user = User()
elif len(rest) == 1:
if not isinstance(rest[0], User):
raise TypeError
user = rest[0]
else:
raise TypeError

self.SAV_PATH = os.path.join(Experiment.SAV_PATH_DIR, f"{content_id}.sav")
if _ExperimentStack.inside(self):
raise errors.ExperimentOpenedError

_summary = user.get_summary(content_id, category)["Data"]
del _summary["$type"]
_experiment = user.get_experiment(_summary["ContentID"])["Data"]
del _experiment["$type"]

if _experiment["Type"] == ExperimentType.Circuit.value:
self.experiment_type = ExperimentType.Circuit
self.PlSav = copy.deepcopy(savTemplate.Circuit)
elif _experiment["Type"] == ExperimentType.Celestial.value:
self.experiment_type = ExperimentType.Celestial
self.PlSav = copy.deepcopy(savTemplate.Celestial)
elif _experiment["Type"] == ExperimentType.Electromagnetism.value:
self.experiment_type = ExperimentType.Electromagnetism
self.PlSav = copy.deepcopy(savTemplate.Electromagnetism)
else:
assert False

self.PlSav["Experiment"] = _experiment
self.PlSav["Summary"] = _summary
_ExperimentStack.push(self)
else:
raise errors.InternalError

Expand Down Expand Up @@ -211,30 +249,6 @@ def __init__(self, open_mode: OpenMode, *args) -> None:
self.StatusSave: dict = {"SimulationSpeed": 1.0, "Elements": []}
else:
raise errors.InternalError
elif open_mode == OpenMode.load_by_plar_app:
content_id, category, *rest = args

if not isinstance(content_id, str) or not isinstance(category, Category):
raise TypeError
if len(rest) == 0:
user = User()
elif len(rest) == 1:
if not isinstance(rest[0], User):
raise TypeError
user = rest[0]
else:
raise TypeError

self.SAV_PATH = os.path.join(Experiment.SAV_PATH_DIR, f"{content_id}.sav")
if _ExperimentStack.inside(self):
raise errors.ExperimentOpenedError

_ExperimentStack.push(self)

_summary = user.get_summary(content_id, category)["Data"]
del _summary["$type"]
_summary["Category"] = category.value
self.PlSav["Summary"] = _summary # 此处应该有问题, 存档不完整
elif open_mode == OpenMode.crt:
sav_name, experiment_type, force_crt, *rest = args

Expand Down Expand Up @@ -293,24 +307,40 @@ def __init__(self, open_mode: OpenMode, *args) -> None:
self.VisionCenter: _tools.position = _tools.position(0, 0 ,0.88)
self.TargetRotation: _tools.position = _tools.position(90, 0, 0)
else:
raise errors.InternalError
assert False

self.entitle(sav_name)
else:
raise errors.InternalError
assert False

assert isinstance(self.open_mode, OpenMode)
assert isinstance(self._elements_position, dict)
assert isinstance(self.Elements, list)
assert isinstance(self.is_load_elements, bool)
assert isinstance(self.SAV_PATH, str)
assert isinstance(self.PlSav, dict)
assert isinstance(self.StatusSave, dict)
assert isinstance(self.CameraSave, dict)
assert isinstance(self.VisionCenter, _tools.position)
assert isinstance(self.TargetRotation, _tools.position)
assert isinstance(self.experiment_type, ExperimentType)
if self.experiment_type == ExperimentType.Circuit:
assert isinstance(self.Wires, set)
assert isinstance(self.is_elementXYZ, bool)
assert isinstance(self.elementXYZ_origin_position, _tools.position)

# TODO 将该函数放到elements.py中
def get_element_from_identifier(self, identifier: str):
''' 通过 原件的["Identifier"]获取元件的引用 '''
''' 通过原件的id获取元件的引用 '''
for element in self.Elements:
assert hasattr(element, "data")
if element.data["Identifier"] == identifier: # type: ignore -> has attr .data
return element
raise errors.ElementNotFound

def _read_CameraSave(self, camera_save: str) -> None:
assert isinstance(camera_save, str)

self.CameraSave = json.loads(camera_save)
temp = eval(f"({self.CameraSave['VisionCenter']})")
self.VisionCenter: _tools.position = _tools.position(temp[0], temp[2], temp[1]) # x, z, y
Expand Down Expand Up @@ -784,7 +814,8 @@ def _get_all_pl_sav() -> List[str]:
savs = savs[savs.__len__() - 1]
return [aSav for aSav in savs if aSav.endswith('sav')]

def _open_sav(sav_path) -> Optional[dict]:
# TODO 不再返回None, 而是直接走异常传播路径
def _open_sav(sav_path) -> dict:
''' 打开一个存档, 返回存档对应的dict
@param sav_path: 存档的绝对路径
'''
Expand Down Expand Up @@ -813,7 +844,11 @@ def encode_sav(path: str, encoding: str) -> Optional[dict]:
else:
with open(sav_path, "rb") as f:
encoding = chardet.detect(f.read())["encoding"]
return encode_sav(sav_path, encoding)
res = encode_sav(sav_path, encoding)
if res is not None:
return res

raise errors.InvalidSavError

def search_experiment(sav_name: str) -> Optional[str]:
''' 检测实验是否存在
Expand All @@ -822,8 +857,9 @@ def search_experiment(sav_name: str) -> Optional[str]:
若存在则返回存档对应的文件名, 若不存在则返回None
'''
for aSav in _get_all_pl_sav():
sav = _open_sav(os.path.join(Experiment.SAV_PATH_DIR, aSav))
if sav is None:
try:
sav = _open_sav(os.path.join(Experiment.SAV_PATH_DIR, aSav))
except errors.InvalidSavError:
continue
if sav["InternalName"] == sav_name:
search_experiment.sav = sav
Expand Down
14 changes: 13 additions & 1 deletion physicsLab/celestial/planets.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,19 @@ def __init__(self, x: numType, y: numType, z: numType) -> None:
class Moon(PlanetBase):
def __init__(self, x: numType, y: numType, z: numType) -> None:
self.data = {
"Identifier": Generate, "Model": "Moon", "Override": None, "Name": "月球", "Parent": None, "Type": 2, "Changed": False, "Extras": {}, "Radius": 1737.1, "RadiusVisible": 0.0116118016, "RotationPeriod": 27.3, "RotationPhase": 0.0, "AxialTilt": 0.0, "Mass": 0.073477, "OrbitType": 0, "OrbitEstimation": 3, "Density": 3.346481005246245, "Gravity": 1.625149040802321, "Luminosity": 0.0, "Temperature": 0.0, "Albedo": 0.12300000339746475, "PowerAbsorbtion": 0.0, "PlanetariumBalance": 0.0, "Position": Generate, "Velocity": Generate, "Acceleration": Generate, "Period": 0.0, "Eccentricity": "NaN", "OmegaUC": 0.0, "OmegaLC": "NaN", "Inclination": "NaN", "Phase": 0.0, "PhaseCurrent": "NaN", "AxisSemi": "NaN", "Perihelion": "NaN", "Aphelion": "NaN", "LeavingKepler": False}
"Identifier": Generate, "Model": "Moon", "Override": None,
"Name": "月球", "Parent": None, "Type": 2, "Changed": False,
"Extras": {}, "Radius": 1737.1, "RadiusVisible": 0.0116118016,
"RotationPeriod": 27.3, "RotationPhase": 0.0, "AxialTilt": 0.0,
"Mass": 0.073477, "OrbitType": 0, "OrbitEstimation": 3,
"Density": 3.346481005246245, "Gravity": 1.625149040802321,
"Luminosity": 0.0, "Temperature": 0.0, "Albedo": 0.12300000339746475,
"PowerAbsorbtion": 0.0, "PlanetariumBalance": 0.0, "Position": Generate,
"Velocity": Generate, "Acceleration": Generate, "Period": 0.0,
"Eccentricity": "NaN", "OmegaUC": 0.0, "OmegaLC": "NaN", "Inclination": "NaN",
"Phase": 0.0, "PhaseCurrent": "NaN", "AxisSemi": "NaN", "Perihelion": "NaN",
"Aphelion": "NaN", "LeavingKepler": False
}

class Chocolate_Ball(PlanetBase):
def __init__(self, x: numType, y: numType, z: numType) -> None:
Expand Down
5 changes: 0 additions & 5 deletions physicsLab/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,6 @@ def __init__(self, err_msg: str = "Index out of range") -> None:
def __str__(self):
return self.err_msg

# 类实例化异常 基类无法被实例化
class instantiateError(Exception):
def __str__(self):
return "This class cannot be instantiated"

class ExperimentError(Exception):
def __init__(self, string: str = "") -> None:
self.err_msg: str = string
Expand Down
1 change: 1 addition & 0 deletions test_pl/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from physicsLab import *

TEST_DIR = os.path.dirname(os.path.abspath(__file__))
TEST_DATA_DIR = os.path.join(TEST_DIR, "data")

USE_VIZTRACER: bool = False

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions test_pl/data/invalid.sav
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
this is not Physics-Lab-AR's save file
41 changes: 32 additions & 9 deletions test_pl/test_physicsLab.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,57 @@ def test_experiment_stack(self):
@my_test_dec
def test_load_all_elements(self):
# 物实导出存档与保存到本地的格式不一样, 因此每种类型的实验都有两种格式的测试数据
expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DIR, "All-Circuit-Elements.sav"))
expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DATA_DIR, "All-Circuit-Elements.sav"))
load_elements(expe)
self.assertTrue(count_elements(expe) == 91)
expe.exit(delete=False)

expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DIR, "Export-All-Circuit-Elements.sav"))
expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DATA_DIR, "Export-All-Circuit-Elements.sav"))
load_elements(expe)
self.assertTrue(count_elements(expe) == 91)
expe.exit()

expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DIR, "All-Celestial-Elements.sav"))
expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DATA_DIR, "All-Celestial-Elements.sav"))
load_elements(expe)
self.assertTrue(count_elements(expe) == 27)
expe.exit()

expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DIR, "Export-All-Celestial-Elements.sav"))
expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DATA_DIR, "Export-All-Celestial-Elements.sav"))
load_elements(expe)
self.assertTrue(count_elements(expe) == 27)
expe.exit()

expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DIR, "All-Electromagnetism-Elements.sav"))
expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DATA_DIR, "All-Electromagnetism-Elements.sav"))
load_elements(expe)
self.assertTrue(count_elements(expe) == 7)
expe.exit()

expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DIR, "Export-All-Electromagnetism-Elements.sav"))
expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DATA_DIR, "Export-All-Electromagnetism-Elements.sav"))
load_elements(expe)
self.assertTrue(count_elements(expe) == 7)
expe.exit()

@my_test_dec
def test_double_load_error(self):
expe = Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DATA_DIR, "All-Circuit-Elements.sav"))
try:
Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DATA_DIR, "All-Circuit-Elements.sav"))
except ExperimentOpenedError:
pass
else:
raise TestError
finally:
expe.exit()

@my_test_dec
def test_load_invalid_sav(self):
try:
Experiment(OpenMode.load_by_filepath, os.path.join(TEST_DATA_DIR, "invalid.sav"))
except InvalidSavError:
pass
else:
raise TestError

@my_test_dec
def test_normal_circuit_usage(self):
expe: Experiment = Experiment(OpenMode.crt, "__test__", ExperimentType.Circuit, True)
Expand Down Expand Up @@ -94,14 +115,16 @@ def test_read_Experiment(self):

@my_test_dec
def test_crt_Experiment(self):
exp: Experiment = Experiment(OpenMode.crt, "__test__", ExperimentType.Circuit, True)
exp.save()
try:
exp: Experiment = Experiment(OpenMode.crt, "__test__", ExperimentType.Circuit, True)
exp.save()
Experiment(OpenMode.crt, "__test__", ExperimentType.Circuit, False) # will fail
except ExperimentExistError:
exp.exit(delete=True)
pass
else:
raise TestError
finally:
exp.exit(delete=True)

@my_test_dec
def test_crt_wire(self):
Expand Down

0 comments on commit 3567abc

Please sign in to comment.