From dcca51a5de097e9a39410b522727b60a3f14bbc0 Mon Sep 17 00:00:00 2001 From: Russ Woodroofe <37375486+RussWoodroofe@users.noreply.github.com> Date: Mon, 1 Mar 2021 10:40:54 +0100 Subject: [PATCH 1/3] create xgap_test.g, a framework to test GAP package mode This framework loads a new instance of GAP run with the -p flag, parses and responds to XGAP queries about fonts and colors, and waits until GAP is ready for input. It then runs a single command, waits until GAP is ready for input (or error input) again, and then closes the child GAP -p instance. All output from the GAP -p instance goes to stdout. The package mode codes are parse and properly displayed: the output should look like that of a normal GAP instance. --- tst/xgap_test.g | 171 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 tst/xgap_test.g diff --git a/tst/xgap_test.g b/tst/xgap_test.g new file mode 100644 index 0000000..c410085 --- /dev/null +++ b/tst/xgap_test.g @@ -0,0 +1,171 @@ +############################################################################# +## +#W xgap_test.g XGAP testing framework Russ Woodroofe +## + +## All globals are prefixed with XGT_ + +## +## TL;DR: Load this file, then perform XGT_Test() for a command +## to be tested in an XGAP or Gap.app style environment. +## +## E.g.: +## XGT_Test("Print(\"Hello world\");"); +## + +## +## Global variables +## +XGT_buf:=""; +XGT_inputmode:=false; + +## +## Constant storing the @w code queries sent by the XGAP library on startup, +## together with appropriate responses. (The responses match those sent by +## Gap.app 0.61, but for most purposes, the specifics shouldn't matter.) +## +## Structure: list of pairs. +## 1st entry: query sent by XGAP library +## 2nd entry: response to send back +## +## Queries: +## 3+XCN is asking for the number of colors supported. (Generally, 2 or 5.) +## 6+XFI lines are asking for metrics of a fixed-spacing font in five sizes +## +XGT_wcode_responses:=[ + ["3+XCN","@a6+I0+I4+"], + ["6+XFII1+","@a21+I0+I7+I3+I6+"], + ["6+XFII2+","@a21+I0+I9+I3+I7+"], + ["6+XFII3+","@a31+I0+I11+I4+I9+"], + ["6+XFII4+","@a41+I0+I21+I4+I01+"], + ["6+XFII5+","@a41+I0+I51+I5+I31+"]];; + +## +#F XGT_ParseChunk( ) +## +## Parse input from "GAP -p" instance up to next @ special code, if any +## + +XGT_ParseChunk:=function(stream) + local atpos, retstr, codechar, pluspos, i; + + atpos:=Position(XGT_buf, '@'); + if atpos = fail then + retstr:=ShallowCopy(XGT_buf); + XGT_buf:=""; + return retstr; + elif atpos > 1 then + retstr:=XGT_buf{[1..atpos-1]}; + XGT_buf:=XGT_buf{[atpos..Length(XGT_buf)]}; + return retstr; + fi; + # So, atpos=1 + if Length(XGT_buf) < 2 then + Info(InfoWarning, 1, "Unexpected @ code end"); + return fail; + fi; + codechar:=XGT_buf[2]; + XGT_buf:=XGT_buf{[3..Length(XGT_buf)]}; + if codechar = '@' then + return "@"; + elif codechar = 'J' then + return "\n"; + elif codechar = 'n' then + #normal output, no action needed + return ""; + elif codechar = 'r' then + #input line, no action needed + return ""; + elif (codechar >= '!' and codechar <= '&') or + (codechar >= '1' and codechar <= '6') then + # if we have a woefully underful buffer, try to get more + if Length(XGT_buf) <= 3 then + Append(XGT_buf, ReadLine(stream)); + fi; + pluspos:=Position(XGT_buf, '+'); + if pluspos = fail then + Info(InfoWarning, 1, "Badly formed garbage collection command"); + return fail; + fi; + XGT_buf:=XGT_buf{[pluspos+1..Length(XGT_buf)]}; + return ""; + elif codechar = 'i' then + XGT_inputmode:=true; + return ""; + elif codechar = 'e' then + XGT_inputmode:=fail; + return ""; + elif codechar = 'w' then + # if we have a woefully underful buffer, try to get more + if Length(XGT_buf) <= 3 then + Append(XGT_buf, ReadLine(stream)); + fi; + for i in [1..Length(XGT_wcode_responses)] do + if StartsWith(XGT_buf, XGT_wcode_responses[i][1]) then + WriteAll(stream, XGT_wcode_responses[i][2]); + XGT_buf:=XGT_buf{[Length(XGT_wcode_responses[i][1])+1..Length(XGT_buf)]}; + return ""; + fi; + od; + Info(InfoWarning, 1, "Unimplemented @w code query @w", XGT_buf); + return "@w"; + else + return Flat(["[@", [codechar], "]"]); + fi; +end; + +## +#F XGT_ParseUntilInput( ) +## +## Parse input from "GAP -p" instance until the instance enters either +## input mode, or error mode +## +XGT_ParseUntilInput:=function(stream) + while XGT_inputmode = false do + Append(XGT_buf, ReadLine(stream)); + while not IsEmpty(XGT_buf) do + Print(XGT_ParseChunk(stream),"\c"); + od; + od; +end; + +## +#F XGT_Test( ) +## +## Start up "GAP -p" instance, running GAP in the package mode ("XGAP mode"). +## Parse XGAP commands, and give canned responses to some basic queries. +## Once "GAP -p" instance is ready for input, issue a single command, then +## wait for the instance to be ready for input (or error input again). +## Close stream (which should close the child "GAP -p" instance) at that +## point. +## +XGT_Test:=function(cmd) + local GAP_cmd, GAP_dir, stream, mycmd; + + GAP_cmd := Filename(DirectoriesLibrary(""), "gap"); + GAP_dir := DirectoryCurrent(); + + XGT_buf:=""; + XGT_inputmode:=false; + + Print("Running GAP in package mode for command: ", cmd, "\n\n"); + + stream := InputOutputLocalProcess(GAP_dir,GAP_cmd,["-p"]); + + if ReadLine(stream) <> "@p1." then + Info(InfoWarning, 1, "Failed acknowledgement from GAP package mode"); + CloseStream(stream); + return fail; + fi; + + XGT_ParseUntilInput(stream); + + WriteAll(stream, cmd); + WriteAll(stream, "\n"); + XGT_inputmode:=false; + + XGT_ParseUntilInput(stream); + + CloseStream(stream); +end; + From 3c1d5901b26a51263efe68c8b4d2862394f5ccf5 Mon Sep 17 00:00:00 2001 From: Russ Woodroofe <37375486+RussWoodroofe@users.noreply.github.com> Date: Thu, 4 Mar 2021 11:57:07 +0100 Subject: [PATCH 2/3] add testall.g which runs all tst/*.tst files in GAP -p environment --- tst/testall.g | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tst/testall.g diff --git a/tst/testall.g b/tst/testall.g new file mode 100644 index 0000000..2054bb2 --- /dev/null +++ b/tst/testall.g @@ -0,0 +1,9 @@ +# +# xgap +# +# This file runs tests for the package mode used by XGAP. +# It is referenced in the package metadata file PackageInfo.g +# + +ReadPackage("xgap", "tst/xgap_test.g"); +XGT_Test("TestDirectory( DirectoriesPackageLibrary(\"xgap\", \"tst\"), rec(testOptions := rec(compareFunction := \"uptowhitespace\") ) );"); From 610ff97960fd48b28686aeee3e63510f4cc1678a Mon Sep 17 00:00:00 2001 From: Russ Woodroofe <37375486+RussWoodroofe@users.noreply.github.com> Date: Thu, 4 Mar 2021 11:58:28 +0100 Subject: [PATCH 3/3] turn on tests --- PackageInfo.g | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PackageInfo.g b/PackageInfo.g index 390b36b..98a8dbc 100644 --- a/PackageInfo.g +++ b/PackageInfo.g @@ -92,7 +92,7 @@ Dependencies := rec( AvailabilityTest := function() return GAPInfo.CommandLineOptions.p; end, -#TestFile := "tst/testall.g", +TestFile := "tst/testall.g", #Keywords := []