Skip to content

Commit

Permalink
Settings - Fixes for whitespaces and comments, added unit tests (#1622)
Browse files Browse the repository at this point in the history
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
  • Loading branch information
johnb432 and PabstMirror committed Oct 24, 2023
1 parent 843ab67 commit 71a08bd
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 22 deletions.
13 changes: 8 additions & 5 deletions addons/settings/fnc_parse.sqf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Description:
Parameters:
_info - Content of file or clipboard to parse. <STRING>
_validate - Check if settings are valid. (optional, default: false) <BOOL>
_source - Can be "client", "mission" or "server" (optional, default: "") <STRING>
Returns:
Settings with values and priority states. <ARRAY>
Expand All @@ -22,14 +23,16 @@ params [["_info", "", [""]], ["_validate", false, [false]], ["_source", "", [""]
private _fnc_parseAny = {
params ["_string"];

// Remove whitespace so parseSimpleArray can handle arrays.
// Means that strings inside arrays don't support white space chars, but w/e.
// No such setting exists atm anyway.
_string = _string splitString _whitespace joinString "";

parseSimpleArray (["[", _string, "]"] joinString "") select 0
};

// If string comes from the "import" button, it is not preprocessed
// Therefore, remove single line comments (//)
_info = _info regexReplace ["/{2}[^\n\r]*((\n|\r)?)", ""];

// Remove multiline comments too (/* */)
_info = _info regexReplace ["/\*[^(\*/)]*((\*/)?)", ""];

// Remove whitespaces at the start and end of each statement, a statement being defined by the ";" at its end
private _parsed = [];

Expand Down
19 changes: 19 additions & 0 deletions addons/settings/test.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// -----------------------------------------------------------------------------
// Automatically generated by 'functions_config.rb'
// DO NOT MANUALLY EDIT THIS FILE!
// -----------------------------------------------------------------------------
#define DEBUG_MODE_FULL
#include "script_component.hpp"

#define TESTS ["parse"]

SCRIPT(test-settings);

// ----------------------------------------------------------------------------

LOG("=== Testing Settings ===");

{
private _test = execVM format ["\x\cba\addons\settings\test_%1.sqf", _x];
waitUntil { scriptDone _test };
} forEach TESTS;
94 changes: 94 additions & 0 deletions addons/settings/test_parse.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// ----------------------------------------------------------------------------
#define DEBUG_MODE_FULL
#include "script_component.hpp"

SCRIPT(test_settings);

// ----------------------------------------------------------------------------

private ["_funcName", "_settings", "_result"];

LOG('Testing Settings');

// UNIT TESTS (parse)
_funcName = QFUNC(parse);
TEST_DEFINED(QFUNC(parse),"");

// Purposely weird formatting, must remain this way because newlines remain part of result
_settings = (preprocessFile "x\cba\addons\settings\test_settings_regular.sqf") call FUNC(parse);
_result = _settings isEqualTo [
["ace_advanced_ballistics_ammoTemperatureEnabled", true, 0],
["ace_advanced_ballistics_barrelLengthInfluenceEnabled", false, 2],
["ace_advanced_ballistics_bulletTraceEnabled", true, 1],
["ace_advanced_fatigue_enabled", false, 0],
["ace_advanced_fatigue_enableStaminaBar", true, 0],
["ace_advanced_fatigue_performanceFactor", 1, 1],
["ace_advanced_fatigue_terrainGradientFactor", 1, 2]
];
TEST_TRUE(_result,_funcName);

_settings = (preprocessFile "x\cba\addons\settings\test_settings_multiline.sqf") call FUNC(parse);
_result = _settings isEqualTo [
["test1", "[
"" item_1 "",
"" item_2 ""
]", 0],
["test2", "[
' item_1 ',
' item_2 '
]", 1],
["test3", "[
' item_1 ' , "" item_2 ""
]", 2],
["test4", "
[
'"" item_1 ""',
' item_2 '
]
", 0]
];
TEST_TRUE(_result,_funcName);

_settings = (preprocessFile "x\cba\addons\settings\test_settings_unicode.sqf") call FUNC(parse);
_result = _settings isEqualTo [["test1", "[Āā, Ăă, Ҙ, привет]", 1]];
TEST_TRUE(_result,_funcName);

_settings = (preprocessFile "x\cba\addons\settings\test_settings_strings.sqf") call FUNC(parse);
_result = _settings isEqualTo [
["test1", "", 0],
["test2", "", 0],
["test3", " T E S T " , 0],
["test4", " T E S T ", 0],
["test5", "[ ' t e s t ' , "" T E S T "" ]", 0],
["test6", "[ "" t e s t "" ,
"""" T E S T """" ]", 0],
["test7", "[ true, false ]", 0],
["test8", "[ "" item_1 "" , "" item_2 "" ]", 0],
["test9", "[ ' item_1 ' , ' item_2 ' ]", 0],
["test10", "[ ' item_1 ' , "" item_2 "" ]", 0],
["test11", "[ '"" item_1 ""' , ' item_2 ' ]", 0],
["test12", "[ ' item_1 ' , ""' item_2 '"" ]", 0]
];
TEST_TRUE(_result,_funcName);

// Don't preprocess for testing comments
_settings = (loadFile "x\cba\addons\settings\test_settings_comments.sqf") call FUNC(parse);
_result = _settings isEqualTo [
["test2", "[true,false]", 1],
["test4", "[ ' t e s t ' , "" T E S T "" ]", 0],
["ace_advanced_ballistics_ammoTemperatureEnabled", true, 0],
["ace_advanced_ballistics_barrelLengthInfluenceEnabled", true, 2],
["ace_advanced_ballistics_bulletTraceEnabled", true, 1]
];
TEST_TRUE(_result,_funcName);

_settings = (loadFile "x\cba\addons\settings\test_settings_comments_eof.sqf") call FUNC(parse);
_result = _settings isEqualTo [
["test1", "[""item_1"",""item_2""]", 1]
];
TEST_TRUE(_result,_funcName);

nil
35 changes: 35 additions & 0 deletions addons/settings/test_settings_comments.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
force test1 = "[""item_1"",""item_2""]";
*/

force test2 = "[true,false]";
/*
//forceforceforce = true;//"[""ACE_DAGR"",""ACE_microDAGR""]";
*/

//test3 = "[Āā,Ăă,Ҙ,привет]";
test4 = "[ ' t e s t ' , "" T E S T "" ]";
/*
test5 = '[ " t e s t ",
"" T E S T "" ]';
test6 = ''; // "settings,";
test7 = " T S T ";
*/


// ACE Advanced Ballistics
ace_advanced_ballistics_ammoTemperatureEnabled = true;
force force ace_advanced_ballistics_barrelLengthInfluenceEnabled = true;
force ace_advanced_ballistics_bulletTraceEnabled = true;

// ACE Advanced Fatigue
/*/*
ace_advanced_fatigue_enabled = true;
ace_advanced_fatigue_enableStaminaBar = true;
/*
force ace_advanced_fatigue_performanceFactor = 1;
force force ace_advanced_fatigue_terrainGradientFactor = 1;
*/

// End of file
5 changes: 5 additions & 0 deletions addons/settings/test_settings_comments_eof.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
force test1 = "[""item_1"",""item_2""]";

// ACE Advanced Fatigue
/*
force test2 = "[true,false]";
28 changes: 28 additions & 0 deletions addons/settings/test_settings_multiline.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
test1 = "[
"" item_1 "",
"" item_2 ""
]";

force test2 = "[
' item_1 ',
' item_2 '
]";

force force test3 =

"[
' item_1 ' , "" item_2 ""
]"

;

test4 = "
[
'"" item_1 ""',
' item_2 '
]
"

;
10 changes: 10 additions & 0 deletions addons/settings/test_settings_regular.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// ACE Advanced Ballistics
ace_advanced_ballistics_ammoTemperatureEnabled = true;
force force ace_advanced_ballistics_barrelLengthInfluenceEnabled = false;
force ace_advanced_ballistics_bulletTraceEnabled = true;

// ACE Advanced Fatigue
ace_advanced_fatigue_enabled = false;
ace_advanced_fatigue_enableStaminaBar = true;
force ace_advanced_fatigue_performanceFactor = 1;
force force ace_advanced_fatigue_terrainGradientFactor = 1;
25 changes: 25 additions & 0 deletions addons/settings/test_settings_strings.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
test1 = "";

test2 = '';

test3 = ' T E S T ';

test4 = " T E S T ";

test5 = "[ ' t e s t ' , "" T E S T "" ]";

test6 = '[ " t e s t " ,
"" T E S T "" ]';

test7 = "[ true, false ]";

test8 = "[ "" item_1 "" , "" item_2 "" ]";

test9 = "[ ' item_1 ' , ' item_2 ' ]";

test10 = "[ ' item_1 ' , "" item_2 "" ]";

test11 = "[ '"" item_1 ""' , ' item_2 ' ]";

test12 = "[ ' item_1 ' , ""' item_2 '"" ]";
1 change: 1 addition & 0 deletions addons/settings/test_settings_unicode.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
force test1 = "[Āā, Ăă, Ҙ, привет]";
3 changes: 3 additions & 0 deletions tools/sqf_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ def main():

print("Validating SQF")

files_to_ignore_lower = [x.lower() for x in ["test_parse.sqf"]]

sqf_list = []
bad_count = 0

Expand All @@ -177,6 +179,7 @@ def main():

for root, dirnames, filenames in os.walk(rootDir + '/' + args.module):
for filename in fnmatch.filter(filenames, '*.sqf'):
if filename.lower() in files_to_ignore_lower: continue
sqf_list.append(os.path.join(root, filename))

for filename in sqf_list:
Expand Down
27 changes: 10 additions & 17 deletions tools/sqfvmChecker.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
import sys
import subprocess
import concurrent.futures
import tomllib

addon_base_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))

files_to_ignore_lower = [
x.lower() for x in ["initSettings.sqf", "initKeybinds.sqf", "XEH_PREP.sqf", "backwards_comp.sqf", "gui_createCategory.sqf"]
x.lower() for x in ["initSettings.sqf", "initKeybinds.sqf", "XEH_PREP.sqf", "backwards_comp.sqf", "gui_createCategory.sqf", "test_settings_comments.sqf", "test_settings_comments_eof.sqf", "test_settings_multiline.sqf", "test_settings_regular.sqf", "test_settings_unicode.sqf"]
]
sqfvm_exe = os.path.join(addon_base_path, "sqfvm.exe")
virtual_paths = [
Expand All @@ -25,22 +26,14 @@ def get_files_to_process(basePath):
if file.lower() in files_to_ignore_lower:
continue
skipPreprocessing = False
addonTomlPath = os.path.join(root, "addon.toml")
if os.path.isfile(addonTomlPath):
with open(addonTomlPath, "r") as f:
tomlFile = f.read()
if "preprocess = false" in tomlFile:
print("'preprocess = false' not supported")
raise
skipPreprocessing = "[preprocess]\nenabled = false" in tomlFile
addonTomlPath = os.path.join(os.path.dirname(root), "addon.toml")
if os.path.isfile(addonTomlPath):
with open(addonTomlPath, "r") as f:
tomlFile = f.read()
if "preprocess = false" in tomlFile:
print("'preprocess = false' not supported")
raise
skipPreprocessing = "[preprocess]\nenabled = false" in tomlFile
for addonTomlPath in [os.path.join(root, "addon.toml"), os.path.join(os.path.dirname(root), "addon.toml")]:
if os.path.isfile(addonTomlPath):
with open(addonTomlPath, "rb") as f:
tomlFile = tomllib.load(f)
try:
skipPreprocessing = not tomlFile.get('rapify')['enabled']
except:
pass
if file == "config.cpp" and skipPreprocessing:
continue # ignore configs with __has_include
filePath = os.path.join(root, file)
Expand Down

0 comments on commit 71a08bd

Please sign in to comment.