diff --git a/.vssbe b/.vssbe index 3f886de..819ac6e 100644 --- a/.vssbe +++ b/.vssbe @@ -10,7 +10,7 @@ { "Enabled": true, "Name": "Prepare", - "Caption": "To prepare directories", + "Caption": "Prepare data and directories", "Mode": { "$type": "net.r_eg.vsSBE.Events.ModeScript, vsSolutionBuildEvent", "Type": "Script", @@ -901,11 +901,11 @@ " {", " const string _CORE = @\"$(fPacked)\";", " const string _OUTPUT = @\"$(fPackMin)\";", - " ", + "", " Func, string[]> gencomb = (_dict, _size, _rule0) =>", " {", " var combination = new char[_size];", - " var set = new List((int)Math.Pow(_dict.Length, _size));", + " var set = new List((int)Math.Pow(_dict.Length, _size));", "", " int pos = 0;", " Action generator = null;", @@ -913,17 +913,17 @@ " {", " for(int i = 0, lim = _size - 1; i < _dict.Length; ++i)", " {", - " if(pos == 0 && !_rule0(i)) {", - " continue;", - " }", + " if(pos == 0 && !_rule0(i)) continue;", "", - " if(pos < lim) {", + " if(pos < lim)", + " {", " combination[pos] = _dict[i];", " ++pos;", " generator();", " --pos;", " }", - " else {", + " else", + " {", " combination[pos] = _dict[i];", " set.Add(new String(combination.ToArray()));", " }", @@ -934,7 +934,14 @@ " return set.ToArray();", " };", "", + " Func review = (input) =>", + " {", + " /* predefined parser behaviour */", + " return Regex.Replace(input, @\"\\s*::&:\\s*&?\", \"\\r\\n\");", + " };", + "", " var variables = new Dictionary();", + " UTF8Encoding utf8noId = new UTF8Encoding(false);", "", " var cdict = new[]", " {", @@ -945,40 +952,40 @@ " // '_'", " };", "", - " var vdict = gencomb(cdict, 2, (i) => { return char.IsLetter(cdict[i]) || cdict[i] == '_'; });", + " string[] vdict = gencomb(cdict, 2, (i) => { return char.IsLetter(cdict[i]) || cdict[i] == '_'; });", "", " // to skip processing for:", " var exvar = new[] { \"__p_call\", \"__p_msb\", \"msb.gnt.cmd\" };", "", " const string VNAME = \"[a-z_][a-z_0-9]+\";", - " using(var reader = new StreamReader(_CORE, System.Text.Encoding.UTF8, true))", + " using(var reader = new StreamReader(_CORE, Encoding.UTF8, true))", " {", - " var content = reader.ReadToEnd();", - " ", + " string content = reader.ReadToEnd();", + "", " /* set /a ERROR_ codes */", - " ", + "", " var errorsCodes = new Dictionary();", " content = Regex.Replace", " (", " content,", - " @\"set\\s+\\/a\\s+(?'k'ERROR_[^= ]+)\\s*=\\s*(?'v'\\d+)\", ", + " @\"set\\s+\\/a\\s+(?'k'ERROR_[^= ]+)\\s*=\\s*(?'v'\\d+)\",", " (m) =>", " {", " errorsCodes[m.Groups[\"k\"].Value] = m.Groups[\"v\"].Value;", " return string.Empty;", " }", " );", - " ", + "", " foreach(var err in errorsCodes)", " {", " content = Regex.Replace(", - " content, ", - " string.Format(\"({1}{0}{1}|{2}{0}{2})\", err.Key, \"%\", \"!\"), ", + " content,", + " string.Format(\"({1}{0}{1}|{2}{0}{2})\", err.Key, \"%\", \"!\"),", " err.Value", " );", " }", - " ", - " ", + "", + "", " /* Shorten variables & labels */", "", " uint uniqVars = 0;", @@ -990,7 +997,7 @@ " (?:\\/\\S\\s+?)?", " (?:\"\"\\s*?)?", " )", - " (?'name'\"+ VNAME + @\")", + " (?'name'\" + VNAME + @\")", " (?'lim'\\s?\\S?=)\", // aq+=1,.. TODO: aq=aq+1 ; aq=1+aq ...", " (m) =>", " {", @@ -998,15 +1005,18 @@ " var vname = m.Groups[\"name\"].Value;", " var lim = m.Groups[\"lim\"].Value;", "", - " if(exvar.Contains(vname)) {", + " if(exvar.Contains(vname))", + " {", " return m.Groups[0].Value;", " }", "", - " if(variables.ContainsKey(vname)) {", + " if(variables.ContainsKey(vname))", + " {", " return def + variables[vname] + lim;", " }", "", - " if(uniqVars + 1 > vdict.Length) {", + " if(uniqVars + 1 > vdict.Length)", + " {", " throw new OverflowException(\"vdict does not contain data for new vars\");", " }", " variables[vname] = vdict[uniqVars++];", @@ -1019,7 +1029,7 @@ " content = Regex.Replace", " (", " content,", - " @\"(?'def'call\\s+:\"+ VNAME + @\"\\s)(?'args'.+?)(?'eol'&|\\r\\n)\", ", + " @\"(?'def'call\\s+:\" + VNAME + @\"\\s)(?'args'.+?)(?'eol'&|\\r\\n)\",", " (m) =>", " {", " var def = m.Groups[\"def\"].Value;", @@ -1033,22 +1043,26 @@ " (_m) =>", " {", " var split = _m.Groups[\"split\"].Value;", - " ", - " if(_m.Groups[\"str\"].Success) {", + "", + " if(_m.Groups[\"str\"].Success)", + " {", " return split + _m.Groups[\"str\"].Value;", " }", - " ", + "", " var vname = _m.Groups[\"name\"].Value;", "", - " if(exvar.Contains(vname)) {", + " if(exvar.Contains(vname))", + " {", " return split + vname;", " }", "", - " if(variables.ContainsKey(vname)) {", + " if(variables.ContainsKey(vname))", + " {", " return split + variables[vname];", " }", "", - " if(uniqVars + 1 > vdict.Length) {", + " if(uniqVars + 1 > vdict.Length)", + " {", " throw new OverflowException(\"vdict does not contain data for new vars\");", " }", " variables[vname] = vdict[uniqVars++];", @@ -1064,20 +1078,21 @@ " content = Regex.Replace", " (", " content,", - " @\"(?'def'(?:[%!]|\\sdefined\\s+))(?'name'\"+ VNAME + \")\", ", + " @\"(?'def'(?:[%!]|\\sdefined\\s+))(?'name'\" + VNAME + \")\",", " (m) =>", " {", " var def = m.Groups[\"def\"].Value;", " var vname = m.Groups[\"name\"].Value;", "", - " if(!variables.ContainsKey(vname)) {", + " if(!variables.ContainsKey(vname))", + " {", " return def + vname;", " }", " return def + variables[vname];", " },", " RegexOptions.IgnoreCase", " );", - " ", + "", " // labels", " content = Regex.Replace", " (", @@ -1089,11 +1104,13 @@ " var label = m.Groups[\"label\"].Value;", " var eol = m.Groups[\"eol\"].Value;", "", - " if(variables.ContainsKey(label)) {", + " if(variables.ContainsKey(label))", + " {", " return def + variables[label] + eol;", " }", "", - " if(uniqVars + 1 > vdict.Length) {", + " if(uniqVars + 1 > vdict.Length)", + " {", " throw new OverflowException(\"vdict does not contain data for new labels\");", " }", " variables[label] = vdict[uniqVars++];", @@ -1105,12 +1122,13 @@ "", " /* exit/B */", "", - " content = Regex.Replace(content, @\"exit\\s*\\/B\\s*(?'code'\\d+)?\\s*?\", (m) => ", + " content = Regex.Replace(content, @\"exit\\s*\\/B\\s*(?'code'\\d+)?\\s*?\", (m) =>", " {", " string ret = \"exit/B\";", " string code = m.Groups[\"code\"].Value;", "", - " if(m.Groups[\"code\"].Success) {", + " if(m.Groups[\"code\"].Success)", + " {", " // 'exit /B 0' is not equal to 'exit /B' - it will pass the latest raised code i.e. without changing it.", " return ret + code;", " }", @@ -1121,21 +1139,22 @@ "", " /* pseudo arguments from labels */", "", - " content = Regex.Replace(content, @\"^\\s*(?'label':\" + VNAME + @\").*?\\r\\n\", (m) => ", + " content = Regex.Replace(content, @\"^\\s*(?'label':\" + VNAME + @\").*?\\r\\n\", (m) =>", " {", " return m.Groups[\"label\"].Value + \"\\r\\n\";", " },", " RegexOptions.IgnoreCase | RegexOptions.Multiline);", "", "", - " /* A common rules */", + " /* predefined data */", "", " content = Regex.Replace(content, @\"(^\\s*?(?:rem|::)\\s+)(?'data'.*?)\\r\\n\", (m) =>", " {", " var data = m.Groups[\"data\"].Value;", - " ", - " if(!data.StartsWith(\"Copyright\") ", - " && !data.StartsWith(\"GetNuTool\") ", + "", + " if(!data.StartsWith(\"Copyright\")", + " && !data.StartsWith(\"GetNuTool\")", + " && !data.StartsWith(\"hMSBuild\")", " && !data.StartsWith(\"http\")", " && !data.StartsWith(\"Based \")", " && !data.StartsWith(\"---\"))", @@ -1143,56 +1162,176 @@ " return string.Empty;", " }", "", - " if(data.Contains(\"/issues\")) {", - " return string.Empty;", - " }", + " if(data.Contains(\"/issues\")) return string.Empty;", "", - " return m.Groups[0].Value;", - " }, ", + " return m.Value;", + " },", " RegexOptions.IgnoreCase | RegexOptions.Multiline);", "", + "", + " /* syntax */", + "", " content = Regex.Replace(content, @\"(\\r\\n)\\s*\", \"$1\");", " content = Regex.Replace(content, @\"\\s+(\\r\\n)\", \"$1\");", - " content = content.Replace(\")\\r\\n)\\r\\n\", \"))\");", " content = content.Replace(\"\\r\\n)\", \")\");", - " content = Regex.Replace(content, @\"\\s*&\\s*if\\s+\", \"&if \", RegexOptions.IgnoreCase);", - "", " content = content.Replace(\"(\\r\\n\", \"(\");", "", - " //TODO: `if` is possible only for `if ... ( ... ) else ...` not `if` ... + & ... `", - " // (^[a-z][:/\\w\\S ]*)\\r\\n(?![:<])", + " Func InlineBlocksIf = null;", + " InlineBlocksIf = (input) =>", + " {", + " if(input.IndexOfAny(new[] { '(', ')' }) == -1) return null;", + " return Regex.Replace", + " (", + " input,", + " @\"", + " (?'lim'^|\\r\\n|[\\s)&])", + " (?'cond'else\\s.*|if\\s.+?(?!\\(x86\\).+?))", + " \\((?'body'", + " (?>", + " [^\\(\\)]", + " |", + " \\((?)", + " |", + " \\)(?<-R>)", + " )*", + " (?(R)(?!))", + " )\\)", + " \",", + " (_m) =>", + " {", + " string lim = _m.Groups[\"lim\"].Value;", + " string cond = _m.Groups[\"cond\"].Value;", + " string body = _m.Groups[\"body\"].Value;", + "", + " string ret = InlineBlocksIf(_m.Groups[\"body\"].Value);", + " if(ret == null) return lim + \"(\" + cond + \"(\" + body + \"))&\";", + "", + " return lim + \"(\" + cond + \"(\" + ret + \"))&\";", + " },", + " RegexOptions.IgnorePatternWhitespace", + " );", + " };", + " //content = InlineBlocksIf(content);", + " content = Regex.Replace(content, @\"\\)\\s*&\\s*\\(\\s*else\\s\", \"else \");", + " content = Regex.Replace(content, @\"\\)\\s*&\\s*\\)\", \"))\");", + " content = Regex.Replace(content, @\"\\)\\s*&\\s*\\r\\n\", \")\\r\\n\");", + "", " content = Regex.Replace", " (", " content,", - " @\"(^(?:set|call|exit|echo|shift|setlocal|endlocal|del)[:/\\w\\S ]*)\\r\\n(?![:<])\",", - " \"$1&\",", + " @\"(^(?:setlocal|endlocal|rmdir|shift|call|exit|echo|del|goto|set)[:/\\w\\S ]*)\\r\\n(?![:<])\",", + " (_m) =>", + " {", + " if(_m.Value.IndexOfAny(new[] { '&', '|' }) != -1) return _m.Value;", + " return _m.Groups[1].Value + \"&\";", + " },", " RegexOptions.Multiline | RegexOptions.IgnoreCase", " );", "", - " content = Regex.Replace(content, @\"\\s+in\\s*\\(([0-9., ]*?)\\)\\s*do\\s*(\\()?\", (Match mfor) =>", + " content = Regex.Replace(content, @\"\\)\\s*\\r\\n\\s*\\(\", \")&(\");", + "", + " content = Regex.Replace(content, @\"\\s+in\\s*\\(([0-9., ]*?)\\)\\s*do\\s*(\\()?\", (mfor) =>", " {", " return string.Format(\" in ({0})do {1}\", mfor.Groups[1].Value.Replace(\" \", \"\"), mfor.Groups[2].Value);", " },", " RegexOptions.IgnoreCase);", "", " content = Regex.Replace(content, @\"\\s*\\)\\s*(else\\s)\", \")$1\", RegexOptions.IgnoreCase);", + " content = Regex.Replace(content, @\"\\(\\s+(goto|set|call)\\s+\", \"($1 \", RegexOptions.IgnoreCase);", + "", + " Func InlineBlocksFor = null;", + " InlineBlocksFor = (input) =>", + " {", + " return Regex.Replace", + " (", + " input,", + " @\"", + " (?'lim'^|\\r\\n|[\\s)&])", + " (?'def'for\\s[^(]+?\\([^)]+?\\)\\s*do\\s*)", + " \\((?'body'", + " (?>", + " [^\\(\\)]", + " |", + " \\((?)", + " |", + " \\)(?<-R>)", + " )*", + " (?(R)(?!))", + " )\\)", + " \\s*&?", + " \",", + " (_m) =>", + " {", + " string lim = _m.Groups[\"lim\"].Value;", + " string def = _m.Groups[\"def\"].Value;", + " string body = _m.Groups[\"body\"].Value;", + "", + " return lim + \"(\" + def + \"(\" + body + \"))&\";", + " },", + " RegexOptions.IgnorePatternWhitespace", + " );", + " };", + " //content = InlineBlocksFor(content);", + " //content = Regex.Replace(content, @\"\\)\\s*&\\s*:\", \")\\r\\n:\");", + "", + "", + " /* line packing */", + "", + " Func splitLongLines = (input, lim, wrd) =>", + " {", + " var spl = new StringBuilder(content.Length + 100);", + " for(int i = 0; i < content.Length;)", + " {", + " int start = i;", + " int end = content.IndexOf(\"\\r\\n\", start + 1);", + " if(end == -1)", + " {", + " spl.Append(content.Substring(start));", + " break;", + " }", + " i = end;", + "", + " int len = end - start;", + " if(len <= lim)", + " {", + " spl.Append(content.Substring(start, len));", + " continue;", + " }", + "", + " int pos = content.IndexOf(wrd, start + lim - wrd.Length);", + " if(pos == -1)", + " {", + " spl.Append(content.Substring(start, end - start));", + " continue;", + " }", + "", + " string a = content.Substring(start, pos - start);", + " spl.AppendLine(a);", + " string b = content.Substring(++pos, end - pos);", + " spl.Append(b);", + " }", + " return spl.ToString();", + " };", + " // max 2047 or 8191 (XP+) characters per line", + " //content = splitLongLines(content, 1700, \"&echo\");", + "", + " using(var writer = new StreamWriter(_OUTPUT, false, utf8noId))", + " writer.Write(review(content));", "", - " using(var writer = new StreamWriter(_OUTPUT, false, new UTF8Encoding(false))) {", - " writer.Write(content);", - " }", " Console.WriteLine(\"{0} -> {1}\", _CORE, _OUTPUT);", " }", "", + " //File.WriteAllText(_CORE, review(File.ReadAllText(_CORE, Encoding.UTF8)), utf8noId);", "", " /* map */", "", - " using(var wmap = new StreamWriter(_CORE + \".map\", false, new UTF8Encoding(false)))", + " using(var wmap = new StreamWriter(_CORE + \".map\", false, utf8noId))", " {", " string map = string.Empty;", " foreach(var v in variables) map += string.Format(\"{0}={1}{2}\", v.Value, v.Key, Environment.NewLine);", " wmap.Write(map);", " }", - " ", + "", " string mtpl =", "@\"", "", @@ -1200,8 +1339,8 @@ "{0}", " ", "\";", - " ", - " using(var wmap = new StreamWriter(_CORE + \".map.targets\", false, new UTF8Encoding(false)))", + "", + " using(var wmap = new StreamWriter(_CORE + \".map.targets\", false, utf8noId))", " {", " string map = string.Empty;", " foreach(var v in variables)", @@ -1217,7 +1356,7 @@ " }", " wmap.Write(string.Format(mtpl, map));", " }", - " ", + "", " return 0;", " }", " }", diff --git a/build.bat b/build.bat index 379786b..c51aa72 100644 --- a/build.bat +++ b/build.bat @@ -12,12 +12,12 @@ call packages\vsSolutionBuildEvent\cim.cmd /v:m /m:7 /p:Configuration=%reltype% setlocal enableDelayedExpansion cd tests - call a initAppVersion - call a execute ..\obj\gnt & call a msgOrFailAt 1 "GetNuTool %appversion%" || goto err - echo Completed as a !msg[1]! + call a initAppVersion Gnt + call a execute ..\obj\gnt & call a msgOrFailAt 1 "GetNuTool %appversionGnt%" || goto err + call a printMsgAt 1 3F "Completed as a " endlocal exit /B 0 :err -echo Failed >&2 + echo Failed build>&2 exit /B 1 \ No newline at end of file diff --git a/tests/_run.bat b/tests/_run.bat index a7250d6..dc5b598 100644 --- a/tests/_run.bat +++ b/tests/_run.bat @@ -4,7 +4,6 @@ :: Tests. Part of https://github.com/3F/GetNuTool :: Based on https://github.com/3F/hMSBuild -call a initAppVersion setlocal enableDelayedExpansion :: path to executable version @@ -13,47 +12,47 @@ set exec=%1 :: path to the directory where the release is located set rdir=%2 -call a isNotEmptyOrWhitespace exec || goto errargs -call a isNotEmptyOrWhitespace rdir || goto errargs +call a isNotEmptyOrWhitespaceOrFail exec || exit /B1 +call a isNotEmptyOrWhitespaceOrFail rdir || exit /B1 + +call a initAppVersion Gnt echo. -echo ------------ -echo Testing -echo ------- +call a cprint 0E ----------------------- +call a cprint F0 "GetNuTool .bat testing" +call a cprint 0E ----------------------- echo. -set /a gcount=0 & set /a failedTotal=0 +if "!gcount!" LSS "1" set /a gcount=0 +if "!failedTotal!" LSS "1" set /a failedTotal=0 :::::::::::::::::: :::::::::::::: ::::::::::::::::::::::::: :: Tests -echo. & call a print "Tests - 'keys'" -call .\keysAndLogicTests gcount failedTotal %exec% %rdir% -@REM echo. & call a print "Tests - 'diffversions'" -@REM call .\diffversions gcount failedTotal %exec% %rdir% %cfull% + echo. & call a print "Tests - 'keys'" + call .\keysAndLogicTests gcount failedTotal %exec% %rdir% + + @REM echo. & call a print "Tests - 'diffversions'" + @REM call .\diffversions gcount failedTotal %exec% %rdir% %cfull% + :::::::::::::::::: :: echo. -echo ################ +call a cprint 0E ---------------- echo [Failed] = !failedTotal! set /a "gcount-=failedTotal" echo [Passed] = !gcount! -echo ################ +call a cprint 0E ---------------- echo. if !failedTotal! GTR 0 goto failed echo. -call a print "All Passed." +call a cprint 0A "All Passed." exit /B 0 :failed echo. - echo. Tests failed. >&2 -exit /B 1 - -:errargs - echo. - echo. Incorrect arguments to start tests. >&2 + call a cprint 0C "Tests failed." >&2 exit /B 1 diff --git a/tests/a.bat b/tests/a.bat index 426b329..49485d8 100644 --- a/tests/a.bat +++ b/tests/a.bat @@ -6,12 +6,13 @@ if "%~1"=="" echo Empty function name & exit /B 1 call :%~1 %2 %3 %4 %5 %6 %7 %8 %9 & exit /B !ERRORLEVEL! :initAppVersion - for /F "tokens=*" %%i in (..\.version) do set appversion=%%i -exit /B 0 + :: [1] - Optional postfix. + for /F "tokens=*" %%i in (..\.version) do set "appversion%~1=%%i" +exit /B :invoke :: (1) - Command. - :: (2) - Input arguments inside "..." via variable. + :: &(2) - Input arguments inside "..." via variable. :: &[3] - Return code. :: !!0+ - Error code from (1) @@ -38,55 +39,207 @@ exit /B !msg[%msgIdx%]! call :invoke "%~1" nul retcode exit /B !retcode! -:startTest - :: (1) - Input arguments to core inside "...". Use ` sign to apply " double quotes inside "...". - :: [2] - Expected return code. Default, 0. +:startExTest + :: (1) - Logic via :label name + :: (2) - Input arguments to core inside "...". Use ` sign to apply " double quotes inside "...". + :: [3] - Expected return code. Default, 0. :: !!1 - Error code 1 if app's error code is not equal [2] as expected. - set "cmd=%~1" - if "%~2"=="" ( set /a exCode=0 ) else set /a exCode=%~2 + set "tArgs=%~2" + if "%~3"=="" ( set /a exCode=0 ) else set /a exCode=%~3 - if "!cmd!" NEQ "" set cmd=!cmd:`="! + if "!tArgs!" NEQ "" set tArgs=!tArgs:`="! set /a gcount+=1 echo. echo - - - - - - - - - - - - echo Test #%gcount% @ %TIME% echo - - - - - - - - - - - - - echo keys: !cmd! + echo keys: !tArgs! echo. - call :invoke "%wdir%%exec%" cmd retcode + set callback=%~1 & shift + + goto %callback% + :_logicExTestEnd if "!retcode!" NEQ "%exCode%" call :failTest & exit /B 1 exit /B 0 +:startTest + :: (1) - Input arguments to core inside "...". Use ` sign to apply " double quotes inside "...". + :: [2] - Expected return code. Default, 0. + :: !!1 - Error code 1 if app's error code is not equal [2] as expected. + + call :startExTest _logicStartTest %* + exit /B + :_logicStartTest + call :invoke "%wdir%%exec%" tArgs retcode + +goto _logicExTestEnd +:: :startTest + +:startABTest + :: (1) - Input arguments inside "...". Use ` sign to apply " double quotes inside "...". + :: (2) - A command + :: (3) - B command + :: &(4) - Result from (2) A + :: &(5) - Result from (3) B + + set "exA=%2" & set "exB=%3" + set "_4=%4" + set "_5=%5" + + call :startExTest _logicStartABTest %1 + exit /B + :_logicStartABTest + call :invoke !exA! tArgs retcodeA & call :getMsgAt 1 outA + call :invoke !exB! tArgs retcodeB & call :getMsgAt 1 outB + + set %_4%=!outA! !retcodeA! + set %_5%=!outB! !retcodeB! + set /a retcode=0 + +goto _logicExTestEnd +:: :startABTest + +:startABStreamTest + :: (1) - Input arguments inside "...". Use ` sign to apply " double quotes inside "...". + :: (2) - A command + :: (3) - B command + :: [4] - Expected return code. Default, 0. + :: &*[5] - Result stream from (2) A; e.g. !%argname%[n+]! + + set "exA=%2" & set "exB=%3" + set "_5=%5" + + call :startExTest _logicStartABStreamTest "-debug %~1" %~4 + exit /B + :_logicStartABStreamTest + + :: Disables time [ 21:50:25.46 ] as [ - ] + set "TIME=-" + + call :invoke !exA! tArgs retcodeA + call :cloneStreamAs _streamA + call :invoke !exB! tArgs retcodeB + + set /a retcode=%retcodeB% + call :eqOriginStreamWithOrFail _streamA 1 || set /a retcode=1 + + set "TIME=" + if defined _5 set %_5%=_streamA + +goto _logicExTestEnd +:: :startABStreamTest + +:abStreamTest + :: (1) - Input arguments inside "...". Use ` sign to apply " double quotes inside "...". + :: (2) - A command + :: (3) - B command + :: [4] - Expected return code. Default, 0. + + call :startABStreamTest "%~1" "%~2" "%~3" %~4 || exit /B 1 + call :completeTest +exit /B 0 + +:startVFTest + :: (1) - Input core application. + :: (2) - Input arguments to core inside "...". Use ` sign to apply " double quotes inside "...". + :: (3) - Full path to actual data in the file system. + :: &(4) - Return actual data. + + set _exapp="%~1" + set _lwrap="%~3" + set "_4=%4" + + call :startExTest _logicStartVFTest %2 + exit /B + :_logicStartVFTest + call :invoke %_exapp% tArgs retcode + for /f "usebackq tokens=*" %%i in (`type %_lwrap%`) do set "%_4%=%%i" + +goto _logicExTestEnd +:: :startVFTest + :completeTest - echo [Passed] + call :cprint 27 [Passed] exit /B 0 :failTest + :: [1] - Optional message string. + set /a "failedTotal+=1" + + if not "%~1"=="" echo %~1 call :printStream failed + echo. & call :cprint 47 [Failed] exit /B 0 :printStream + if "!msgIdx!"=="" exit /B 1 for /L %%i in (0,1,!msgIdx!) do echo (%%i) *%~1: !msg[%%i]! exit /B 0 +:printStreamAB + :: &(1) - Stream name to print together with origin. + + if "!msgIdx!"=="" exit /B 1 + for /L %%i in (0,1,!msgIdx!) do ( + echo `!_streamA[%%i]!` & echo `!msg[%%i]!` & echo -- + ) +exit /B 0 + +:failStreamsTest + :: &(1) - Stream name to print together with origin. + :: [2] - Don't count in the total counter if 1. + + if "%~2" NEQ "1" set /a "failedTotal+=1" + call :printStreamAB %~1 +exit /B 0 + :contains - :: (1) - input string via variable - :: (2) - substring to check - :: &(3) - result, 1 if found. + :: &(1) - Input string via variable + :: (2) - Substring to check. Use ` instead of " and do NOT use =(equal sign) since it's not protected. + :: &(3) - Result, 1 if found. + + :: TODO: L-39 protect from `=` like the main module does; or compare in parts using `#` set "input=!%~1!" if "%~2"=="" if "!input!"=="" set /a %3=1 & exit /B 0 if "!input!"=="" if not "%~2"=="" set /a %3=0 & exit /B 0 + set "input=!input:"=`!" set "cmp=!input:%~2=!" - if .!cmp! NEQ .!input! ( set /a %3=1 ) else set /a %3=0 + if "!cmp!" NEQ "!input!" ( set /a %3=1 ) else set /a %3=0 +exit /B 0 + +:printMsgAt + :: (1) - index at msg + :: [2] - color attribute via :color call + :: [3] - prefixed message at the same line + :: !!1 - Error code 1 if &(1) is empty or not valid. + + call :getMsgAt %~1 _msgstr || exit /B 1 + + if not "%~2"=="" ( + call :cprint %~2 "%~3!_msgstr!" + + ) else echo !_msgstr! +exit /B 0 + +:getMsgAt + :: (1) - index at msg + :: &(2) - result string + :: !!1 - Error code 1 if &(1) is empty or not valid. + + if "%~1"=="" exit /B 1 + if %msgIdx% LSS %~1 exit /B 1 + if %~1 LSS 0 exit /B 1 + + set %2=!msg[%~1]! exit /B 0 :msgAt @@ -95,12 +248,9 @@ exit /B 0 :: &(3) - result, 1 if found. set /a %3=0 + call :getMsgAt %~1 _msgstr || exit /B 0 - if "%~1"=="" exit /B 0 - if %msgIdx% LSS %~1 exit /B 0 - if %~1 LSS 0 exit /B 0 - - call :contains msg[%~1] "%~2" n & set /a %3=!n! + call :contains _msgstr "%~2" _n & set /a %3=!_n! exit /B 0 :msgOrFailAt @@ -108,7 +258,7 @@ exit /B 0 :: (2) - substring to check :: !!1 - Error code 1 if the message is not found at the specified index. - call :msgAt %~1 "%~2" n & if .!n! NEQ .1 call :failTest & exit /B 1 + call :msgAt %~1 "%~2" _n & if .!_n! NEQ .1 call :failTest & exit /B 1 exit /B 0 :checkFs @@ -125,8 +275,8 @@ exit /B 0 :: (2) - Path to the file that must exist. :: !!1 - Error code 1 if the directory or file does not exist. - call :checkFs "%basePkgDir%%~1" "%~2" || exit /B 1 -exit /B 0 + call :checkFs "%basePkgDir%%~1" "%~2" +exit /B :checkFsNo :: (1) - Path to the file or directory that must NOT exist. @@ -139,11 +289,12 @@ exit /B 0 :: (1) - Path to the file or directory that must NOT exist. :: !!1 - Error code 1 if the specified path exists. - call :checkFsNo "%basePkgDir%%~1" || exit /B 1 -exit /B 0 + call :checkFsNo "%basePkgDir%%~1" +exit /B :unsetDir :: (1) - Path to directory. + call :isStrNotEmptyOrWhitespaceOrFail "%~1" || exit /B 1 rmdir /S/Q "%~1" 2>nul exit /B 0 @@ -154,6 +305,7 @@ exit /B 0 :unsetFile :: (1) - File name. + call :isStrNotEmptyOrWhitespaceOrFail "%~1" || exit /B 1 del /Q "%~1" 2>nul exit /B 0 @@ -171,28 +323,70 @@ exit /B 0 :findInStream :: (1) - substring to check - :: &(2) - result, 1 if found. - - for /L %%i in (0,1,!msgIdx!) do ( - call :msgAt %%i "%~1" n & if .!n! EQU .1 ( - set /a %2=1 + :: [2] - Start index, 0 by default. + :: &[3] - Return index or -1 if not found. + :: !!1 - Error code 1 if failed. + :: !!3 - Error code 3 if not found. + + if "%~2"=="" (set /a _sidx=0) else set /a _sidx=%~2 + if %_sidx% LSS 0 exit /B 1 + if %msgIdx% LSS %_sidx% exit /B 1 + + for /L %%i in (%_sidx%,1,!msgIdx!) do ( + call :msgAt %%i "%~1" _n & if .!_n! EQU .1 ( + if not "%~3"=="" set /a %3=%%i exit /B 0 ) ) - set /a %2=0 + if not "%~3"=="" set /a %3=-1 +exit /B 3 + +:findInStreamOrFail + :: (1) - substring to check + :: [2] - Start index, 0 by default. + :: &[3] - Return index or -1 if not found. + :: !!1 - Error code 1 if failed. + + call :findInStream "%~1" %~2 %~3 || ( call :failTest & exit /B 1 ) exit /B 0 :failIfInStream :: (1) - substring to check :: !!1 - Error code 1 if the input (1) was not found. - call :findInStream "%~1" n & if .!n! EQU .1 call :failTest & exit /B 1 + call :findInStream "%~1" n & if .!n! EQU .1 ( call :failTest & exit /B 1 ) exit /B 0 :print :: (1) - Input string. - echo.[ %TIME% ] %~1 + :: NOTE: delayed `dmsg` because symbols like `)`, `(` ... requires protection after expansion. L-32 + set "dmsg=%~1" & echo [ %TIME% ] !dmsg! +exit /B 0 + +:cprint + :: (1) - color attribute via :color call + :: (2) - Input string. + + call :color %~1 "%~2" & echo. +exit /B 0 + +:color + :: (1) - color attribute, {background} | {foreground} + :: 0 = Black 8 = Gray + :: 1 = Blue 9 = Light Blue + :: 2 = Green A = Light Green + :: 3 = Aqua B = Light Aqua + :: 4 = Red C = Light Red + :: 5 = Purple D = Light Purple + :: 6 = Yellow E = Light Yellow + :: 7 = White F = Bright White + + :: (2) - Input string. + + "%~2" + findstr /a:%~1  "%~2" nul + del "%~2">nul exit /B 0 :isNotEmptyOrWhitespace @@ -219,3 +413,51 @@ exit /B 0 :: &(2) - sha1 result. set %2=!msg[%~1]:~45,40! exit /B 0 + +:errargs + echo. + echo. Incorrect arguments. >&2 +exit /B 1 + +:isNotEmptyOrWhitespaceOrFail + :: &(1) - Input variable. + :: !!1 - Error code 1 if &(1) is empty or contains only whitespace characters. + call :isNotEmptyOrWhitespace %1 || (call :errargs & exit /B 1) +exit /B 0 + +:isStrNotEmptyOrWhitespaceOrFail + :: (1) - Input string. + :: !!1 - Error code 1 if (1) is empty or contains only whitespace characters. + set "_wstrv=%~1" + call :isNotEmptyOrWhitespaceOrFail _wstrv +exit /B + +:cloneStreamAs + :: &(1) - Destination. + + for /L %%i in (0,1,!msgIdx!) do set "%~1[%%i]=!msg[%%i]!" +exit /B + +:eqOriginStreamWith + :: &(1) - Current stream with stream from (1). + :: &(2) - Return 1 if both streams are equal. + + for /L %%i in (0,1,!msgIdx!) do ( + if not "!%~1[%%i]!"=="!msg[%%i]!" ( set "%2=0" & exit /B 0 ) + ) + set "%2=1" +exit /B 0 + +:eqOriginStreamWithOrFail + :: &(1) - Current stream with stream from (1). + :: [2] - Don't count in the total counter if 1. + + call :eqOriginStreamWith %~1 _r & if !_r! EQU 0 ( + call :failStreamsTest %~1 %~2 & exit /B 1 + ) +exit /B 0 + +:disableAppVersion + :: [1] - Optional postfix. + set "appversion%~1=off" +exit /B 0 \ No newline at end of file diff --git a/tests/keysAndLogicTests.bat b/tests/keysAndLogicTests.bat index c03a502..1c76355 100644 --- a/tests/keysAndLogicTests.bat +++ b/tests/keysAndLogicTests.bat @@ -4,9 +4,10 @@ :: Tests. Part of https://github.com/3F/GetNuTool setlocal enableDelayedExpansion +call a isNotEmptyOrWhitespaceOrFail %~1 || exit /B1 set /a gcount=!%~1! & set /a failedTotal=!%~2! -set exec=%~3 & set wdir=%~4 +set "exec=%~3" & set "wdir=%~4" :::::::::::::::::: :::::::::::::: ::::::::::::::::::::::::: :: Tests @@ -29,7 +30,11 @@ set exec=%~3 & set wdir=%~4 call a startTest "" 1 || goto x call a msgOrFailAt 0 "" || goto x - call a msgOrFailAt 1 "GetNuTool %appversion%" || goto x + + if not defined appversionGnt call a failTest "Empty *appversionGnt" & goto x + if not "%appversionGnt%"=="off" ( + call a msgOrFailAt 1 "GetNuTool %appversionGnt%" || goto x + ) call a msgOrFailAt 2 "github/3F" || goto x call a msgOrFailAt 3 "Empty .config + ngpackages" || goto x call a completeTest @@ -40,7 +45,11 @@ set exec=%~3 & set wdir=%~4 call a startTest "/p:debug=true" 1 || goto x call a msgOrFailAt 0 "" || goto x - call a msgOrFailAt 1 "GetNuTool %appversion%" || goto x + + if not defined appversionGnt call a failTest "Empty *appversionGnt" & goto x + if not "%appversionGnt%"=="off" ( + call a msgOrFailAt 1 "GetNuTool %appversionGnt%" || goto x + ) call a msgOrFailAt 2 "github/3F" || goto x call a msgOrFailAt 3 "packages.config is not found" || goto x call a msgOrFailAt 4 ".tools\packages.config is not found" || goto x @@ -447,7 +456,7 @@ call :cleanup :: :x endlocal & set /a %1=%gcount% & set /a %2=%failedTotal% -if "!failedTotal!"=="0" exit /B 0 +if !failedTotal! EQU 0 exit /B 0 exit /B 1 :cleanup