From b78cbae4226f3245369353795f5f2546ed380677 Mon Sep 17 00:00:00 2001 From: cclecle Date: Thu, 28 Sep 2023 23:34:54 +0100 Subject: [PATCH] fix: correct the code to add non existing keys in COD4 cfg files --- src/pygamecfg/core_gamecfg.py | 14 +++++++++++--- src/pygamecfg/game_cod4.py | 17 ++++++++++------- test/data/COD4/main/server.cfg | 2 +- test/test_cod4.py | 15 ++++++++++++--- test/test_ut99.py | 3 --- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/pygamecfg/core_gamecfg.py b/src/pygamecfg/core_gamecfg.py index fbd7d51..915c5f8 100644 --- a/src/pygamecfg/core_gamecfg.py +++ b/src/pygamecfg/core_gamecfg.py @@ -19,6 +19,14 @@ from abc import ABCMeta, abstractmethod from enum import Enum +class GameCfgException(Exception): + """Standard Exception to catch non existing key in configuration file""" + + +class OptionNotFoundError(GameCfgException): + """Standard Exception to catch non existing configuration option""" + + class OptionType(Enum): """Supported option data type""" @@ -145,7 +153,7 @@ class GameOptions_Factory: with _option(self.GameRootDir, self.ConfigFileRelPath) as _optionInst: _optionInst.set(_optionInst.format(value)) return - raise RuntimeError("Option not found") + raise OptionNotFoundError("Option not found") def rem(self, OptionName: str, value: Union[None, str]) -> None: """generic rem function (API call)""" @@ -154,7 +162,7 @@ class GameOptions_Factory: with _option(self.GameRootDir, self.ConfigFileRelPath) as _optionInst: _optionInst.rem(value) return - raise RuntimeError("Option not found") + raise OptionNotFoundError("Option not found") def get(self, OptionName: str) -> Union[str, list[str]]: """generic get function (API call)""" @@ -162,7 +170,7 @@ class GameOptions_Factory: if _option.szOptionName == OptionName: with _option(self.GameRootDir, self.ConfigFileRelPath) as _optionInst: return _optionInst.get() - raise RuntimeError("Option not found") + raise OptionNotFoundError("Option not found") def GameOptions_Factory_Register(cls: type[GameOption]) -> type[GameOption]: diff --git a/src/pygamecfg/game_cod4.py b/src/pygamecfg/game_cod4.py index 08aa516..15db995 100644 --- a/src/pygamecfg/game_cod4.py +++ b/src/pygamecfg/game_cod4.py @@ -17,7 +17,11 @@ import re from os.path import join from os import linesep -from .core_gamecfg import GameOptions_Factory_Register, GameOption, OptionType +from .core_gamecfg import GameOptions_Factory_Register, GameOption, OptionType, GameCfgException + + +class COD4KeyNotFoundError(GameCfgException): + """Exception to catch non existing configuration key in COD4 configuration file""" class GameOption_COD4(GameOption): @@ -27,7 +31,7 @@ class GameOption_COD4(GameOption): szOptionName: str = "" szKeyName: str = "" bDblQuoted: bool = False - szPrefix = "" + szPrefix: str = "" def __init__(self, GameRootDir: str, ConfigFileRelPath: str) -> None: super().__init__(GameRootDir, ConfigFileRelPath) @@ -47,9 +51,8 @@ class GameOption_COD4(GameOption): FinalValue: str = value if self.bDblQuoted: FinalValue = '"' + FinalValue + '"' - if self.szPrefix: + if self.szPrefix != "": FinalValue = self.szPrefix + " " + self.szKeyName + " " + FinalValue + linesep - bfound = False newFile = "" @@ -66,7 +69,7 @@ class GameOption_COD4(GameOption): if not bfound: # write new key at the top of the file to be sure we do not erase the map / map_rotate cmd - newFile = value + newFile + newFile = FinalValue + newFile self.cfgfile.close() with open(self.mainConfigFilePath, "w", encoding="utf8") as ofile: @@ -89,7 +92,7 @@ class GameOption_COD4(GameOption): else: newFile += line if not bfound: - raise RuntimeError("Option not found in file") + raise COD4KeyNotFoundError("Option not found in file") self.cfgfile.close() with open(self.mainConfigFilePath, "w", encoding="utf8") as ofile: @@ -113,7 +116,7 @@ class GameOption_COD4(GameOption): res = result.groupdict()["value"] bfound = True if not bfound: - raise RuntimeError("Option not found in file") + raise COD4KeyNotFoundError("Option not found in file") return res diff --git a/test/data/COD4/main/server.cfg b/test/data/COD4/main/server.cfg index c91ce60..1b4ac75 100644 --- a/test/data/COD4/main/server.cfg +++ b/test/data/COD4/main/server.cfg @@ -24,7 +24,7 @@ set g_log "games_mp.log" set sv_log_damage "1" set sv_statusfile "serverstatus.xml" -set net_port 28960 +//set net_port 28960 set sv_minPing "0" diff --git a/test/test_cod4.py b/test/test_cod4.py index c90dc03..ee586ae 100644 --- a/test/test_cod4.py +++ b/test/test_cod4.py @@ -15,14 +15,12 @@ import shutil from src import pygamecfg from src.pygamecfg.__main__ import fct_main +from src.pygamecfg.game_cod4 import COD4KeyNotFoundError testdir_path = Path(__file__).parent.resolve() class Testtest_cod4(unittest.TestCase): - def tearDown(self) -> None: - self.CleanTmp() - def setUp(self) -> None: chdir(testdir_path.parent.resolve()) self.CleanTmp() @@ -65,3 +63,14 @@ class Testtest_cod4(unittest.TestCase): self.assertEqual("", capted_stderr.getvalue()) # check if other key still there / untouched self.test_normal_READ_sv_mapRotation() + + def test_defect_READ_net_port_NONEXISTS(self): + with self.assertRaises(COD4KeyNotFoundError): + fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "net_port"]) + + def test_normal_WRITE_net_port_NONEXISTS(self): + fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "SetOption", "net_port", "132"]) + with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(StringIO()) as capted_stderr: + fct_main(["-g", "cod4", "-b", "test/tmp/COD4", "GetOption", "net_port"]) + self.assertEqual("132\n", capted_stdout.getvalue()) + self.assertEqual("", capted_stderr.getvalue()) diff --git a/test/test_ut99.py b/test/test_ut99.py index 39ee258..369962c 100644 --- a/test/test_ut99.py +++ b/test/test_ut99.py @@ -20,9 +20,6 @@ testdir_path = Path(__file__).parent.resolve() class Testtest_ut99(unittest.TestCase): - def tearDown(self) -> None: - self.CleanTmp() - def setUp(self) -> None: chdir(testdir_path.parent.resolve()) self.CleanTmp()