6 IDESettings ideSettings;
8 IDESettingsContainer settingsContainer
10 dataOwner = &ideSettings;
11 dataClass = class(IDESettings);
14 IDEConfigHolder ideConfig { };
16 Test dummy; // FIXME ugly hack
18 GlobalSettings globalSettings { };
24 void OnDisplay(Surface surface,
25 int x, int y, int width,
28 DataDisplayFlags flags)
30 ColorKey keys[] = {{Color {digest[0] , digest[1] , digest[2] }, 0.0f},
31 {Color {digest[3] , digest[4] , digest[5] }, 0.2f},
32 {Color {digest[6] , digest[7] , digest[8] }, 0.4f},
33 {Color {digest[9] , digest[10], digest[11]}, 0.6f},
34 {Color {digest[12], digest[13], digest[14]}, 0.8f},
35 {Color {digest[15], digest[0] , digest[1] }, 1.0f}};
37 surface.Gradient(keys, 6, 0, horizontal, x+1, y+1, x+34, y+14);
38 surface.Rectangle(x+1,y+1,x+34,y+14);
41 void OnSerialize(IOChannel channel)
43 channel.WriteData(digest,16);
45 void OnUnserialize(IOChannel channel)
47 channel.ReadData(digest,16);
52 TempFile hashTemp { };
54 Array<OutputFile> files = AccessMacros::allOutputFiles(value);
57 File f = of.outputFile;
63 uint count = f.Read(buffer,1,sizeof(buffer));
64 hashTemp.Write(buffer, 1, count);
73 size = (uint)hashTemp.GetSize();
74 MD5Update(&ctx, hashTemp.buffer, size);
75 MD5Final(digest, &ctx);
81 // TOFIX: When this is commented out, no warning at conversion but conversion not acting as such!!
86 CompilerConfig defaultCompiler;
88 void CreateMakefile(String epjPath, String makePath)
92 char* configName = null;//"release";
94 if(false) //noGlobalSettings)
96 defaultCompiler = MakeDefaultCompiler("Default", true);
101 const char * compiler = getenv("COMPILER");
102 if(!compiler) compiler = "Default";
104 // TODO: Command line option to choose between the two
105 // or a command line option to not use global settings
106 //defaultCompiler = MakeDefaultCompiler();
107 defaultCompiler = ideConfig.compilers.GetCompilerConfig(compiler);
108 // possible TODO: use the workspace to select the active compiler
109 // TODO: option to specify compiler name when using global settings
111 defaultCompiler.eccCommand = "ecc -nolinenumbers";
113 if(FileExists(epjPath).isFile)
115 char extension[MAX_EXTENSION] = "";
116 GetExtension(epjPath, extension);
118 if(!strcmp(extension, ProjectExtension))
120 project = LoadProject(epjPath, "Debug");
123 ProjectConfig defaultConfig = null;
127 for(config : project.configurations)
129 if(!strcmpi(configName, config.name))
131 project.config = config;
137 printf("Error: Project configuration (%s) was not found.\n", configName);
141 ProjectConfig releaseConfig;
142 for(config : project.configurations)
144 if(!strcmpi(config.name, "Release"))
146 project.config = config;
147 releaseConfig = config;
151 if(!releaseConfig && project.configurations.count)
153 project.config = project.configurations.firstIterator.data;
155 releaseConfig = project.configs.first;
156 releaseConfig.objDir.dir = "release";
157 releaseConfig.targetDir.dir = "release";
158 releaseConfig.optimize = forSpeed;
159 releaseConfig.debug = false;
160 releaseConfig.name = "Release";
166 printf("Error: There are no Project configurations.\n");
168 // we don't need to create a config to compile a config-less project, do we?
170 char targetName[MAX_FILENAME];
171 GetLastDirectory(epjPath, targetName);
172 StripExtension(targetName);
173 defaultConfig = ProjectConfig
176 targetType = executable;
177 targetName = targetName;
178 defaultNameSpace = "";
179 objDir.dir = "release";
180 targetDir.dir = "release";
184 makingModified = true;
185 compilingModified = true;
186 linkingModified = true;
188 project.config = defaultConfig;
194 project.GenerateCrossPlatformMk(null);
195 project.GenerateCompilerCf(defaultCompiler, true);
196 project.GenerateMakefile(makePath, false, null, project.config);
199 delete defaultConfig;
211 String filePath "filePath";
212 TestRun reference "reference";
213 bool active "active";
221 dbtable "OutputFiles" OutputFile
224 File outputFile "outputFile";
225 String filePath "filePath";
228 OutputFileType type "type";
229 DateTime created "created";
233 dbtable "Runs" TestRun
236 File makeOutput "makeOutput";
237 int makeReturnValue "makeReturnValue";
239 TimeStamp time "time";
241 MD5Digest digest "digest";
242 dbindex test, time testAndTime;
249 TestRun ::lastTestRun(Test t)
252 Row tRow { tbl = dbindex("Runs", testAndTime) };
253 if(tRow.Find(dbfield("Runs",test),middle,nil,t)) {
259 Array<TestRun> ::allTestRuns(Test t)
261 Array<TestRun> runs { };
262 Row tRow { tbl = dbindex("Runs",testAndTime) };
263 for(tRow.Find(dbfield("Runs",test),middle,nil,t); !tRow.nil; tRow.Find(dbfield("Runs", test), next, nil, t)) //Next())
264 runs.Add(tRow.sysID);
268 Array<OutputFile> ::allOutputFiles(TestRun t)
270 Array<OutputFile> files { };
271 RowOutputFiles tRow { tbl = dbindex("OutputFiles",run) };
272 for(tRow.Find(dbfield("OutputFiles",run),middle,nil,t); !tRow.nil; tRow.Find(dbfield("OutputFiles", run), next, nil, t)) //tRow.Next())
276 files.Add(tRow.sysID);
283 class TestSuiteGlobalSettings : GlobalAppSettings
285 settingsName = "testSuite";
288 ~TestSuiteGlobalSettings()
293 void OnAskReloadSettings()
297 public SettingsIOResult Load()
299 SettingsIOResult result = GlobalAppSettings::Load();
300 if(result == success)
304 GetGlobalValue("Tools","diff", singleString, &diffTool);
305 GetGlobalValue("Tests","list", singleString, &testDB_file);
311 public SettingsIOResult Save()
313 SettingsIOResult result = GlobalAppSettings::Save();
314 if(result == success)
316 PutGlobalValue("Tools","diff", singleString, diffTool);
317 PutGlobalValue("Tests","list", singleString, testDB_file);
324 class DiffThread : Thread
326 char origDir[MAX_LOCATION];
327 char newDir[MAX_LOCATION];
332 FileListing flOrig { origDir, 0 };
333 FileListing flNew { newDir, 0 };
334 diff = DualPipeOpenf({ true }, "%s \"%s\" \"%s\"", theGlobalSettings.diffTool, origDir, newDir);
341 DeleteFile(flOrig.path);
346 DeleteFile(flNew.path);
352 void DiffDir(Array<OutputFile> outputOrig, Array<OutputFile> outputNew)
354 //char origDir[MAX_LOCATION];
355 //char newDir[MAX_LOCATION];
356 CreateTemporaryDir(origDir, "TestSuiteOrigDir");
357 CreateTemporaryDir(newDir,"TestSuiteNewDir");
359 for(d : [ outputOrig, outputNew ])
363 char tmpname[MAX_LOCATION];
364 char dummybuffer[MAX_LOCATION];
365 File outputFile = of.outputFile;
369 GetLastDirectory(of.filePath, dummybuffer);
370 strcpy(tmpname, (d == outputOrig) ? origDir : newDir);
371 PathCat(tmpname, dummybuffer);
372 tmp = FileOpen(tmpname, write);
375 CopyFile(outputFile, tmp);
389 int GenerateMakefile(Test t)
391 //DualPipe epj2makePipe;
392 char testFolder[MAX_LOCATION];
393 char makefileOut[MAX_LOCATION];
394 char epjName[MAX_LOCATION];
395 char * filePath = t.filePath;
398 StripLastDirectory(filePath, testFolder);
399 PathCat(testFolder, "release");
403 StripLastDirectory(filePath, testFolder);
404 GetLastDirectory(filePath, epjName);
405 strcpy(makefileOut, testFolder);
406 PathCat(makefileOut, "project-testingSuite.Makefile");
408 // epj2makePipe = DualPipeOpenf({ output = true },"epj2make -l /usr/ecere/lib -o %s %s > /dev/null", makefileOut, t.filePath);
409 //epj2makePipe = DualPipeOpenf({ output = true },"epj2make -cpp cpp -l /usr/ecere/lib -o %s %s", makefileOut, filePath);
410 //epj2makePipe.Wait();
411 CreateMakefile(filePath, makefileOut);
414 //return epj2makePipe.GetExitCode();
418 char* Copy2Temp(File f, String tmpPath)
421 char tmpFilename[MAX_LOCATION];
422 tmp = CreateTemporaryFile(tmpFilename, tmpPath);
425 return CopyString(tmpFilename);
428 int BuildTest(TestRun run)
431 int makeSuccess = -1;
432 char makefileOut[MAX_LOCATION];
433 char * filePath = run.test.filePath;
434 char oldDir[MAX_LOCATION];
435 StripLastDirectory(filePath, makefileOut);
437 GetWorkingDir(oldDir, sizeof(oldDir));
438 ChangeWorkingDir(makefileOut);
439 PathCat(makefileOut, "project-testingSuite.Makefile");
441 //Execute("make -f %s clean", makefileOut);
443 makePipe = DualPipeOpenf({ output = true },"%s -f %s clean", defaultCompiler.makeCommand, makefileOut);
447 char makeBuffer[1024];
449 while(!makePipe.Eof())
451 count = makePipe.Read(makeBuffer,1,sizeof(makeBuffer));
452 f.Write(makeBuffer, 1, count);
458 makePipe = DualPipeOpenf({ output = true },"%s -f %s", defaultCompiler.makeCommand, makefileOut);
462 char makeBuffer[1024];
464 while(!makePipe.Eof())
466 count = makePipe.Read(makeBuffer,1,sizeof(makeBuffer));
467 f.Write(makeBuffer, 1, count);
471 ChangeWorkingDir(oldDir);
472 makeSuccess = makePipe.GetExitCode();
473 run.makeReturnValue = makeSuccess;
478 void AddOutputFiles(TestRun run)
480 char testFolder[MAX_LOCATION];
482 char * filePath = run.test.filePath;
483 StripLastDirectory(filePath, testFolder);
485 // TODO: Get from config
486 PathCat(testFolder, "obj/release.win32");
488 fl = { testFolder, extensions = "c, ec, sym, imp" }; // ["c", "ec", "sym", "imp"] perhaps?
492 RowOutputFiles of { };
493 char extension[MAX_LOCATION];
494 DateTime rightNow { };
495 f = FileOpen(fl.path, read);
500 of.filePath = fl.path;
503 GetExtension(fl.path, extension);
504 if(!strcmp(extension,"c"))
508 else if(!strcmp(extension,"ec"))
512 else if(!strcmp(extension,"sym"))
516 else if(!strcmp(extension,"imp"))
520 rightNow.GetLocalTime();
521 of.created = (TimeStamp)rightNow;
528 void CopyFile(File input, File output)
531 input.Seek(0, start);
534 uint count = input.Read(buffer, 1, sizeof(buffer));
537 output.Write(buffer, 1, count);
542 class RelativeTimeStamp : TimeStamp
544 const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
552 rightNow = (TimeStamp)dt;
553 count = (int64)(rightNow - (TimeStamp)this);
606 PrintBuf(tempString, 1024, "<1 minute ago");
610 PrintBuf(tempString, 1024, count, " ", units, (count > 1)? "s" : "", " ago");
619 void OnDisplay(Surface surface,
620 int x, int y, int width,
623 DataDisplayFlags flags)
628 b = theTestSuiteWindow.makeSuccess.bitmap;
632 b = theTestSuiteWindow.makeFailure.bitmap;
634 surface.Blit(b, x, y, 0, 0, b.width, b.height);
638 class TestSuiteWindow : Window
640 text = "Ecere Compiler Tests";
641 background = activeBorder;
642 borderStyle = sizable;
647 anchor = { horz = -3, vert = 80 };
649 BitmapResource makeSuccess { ":check.png" , window = this };
650 BitmapResource makeFailure { ":x.png", window = this };
654 testListBox.AddField(fieldName);
655 testListBox.AddField(fieldActive);
657 runsListBox.AddField(fieldBuildStatus);
658 runsListBox.AddField(fieldAuraColor);
659 runsListBox.AddField(fieldRun);
660 runsListBox.AddField(fieldSaved);
661 // LoadTests(); FIXME this causes a segfault (but not OnCreate)
662 Print("starting up...\n");
665 PaneSplitter windowPanes
667 this, leftPane = testListBox, rightPane = runSection, split = 200;
671 this, anchor = { top = 0, bottom = 30, left = 0, right = 0 };
673 PaneSplitter runPanes
675 runSection, leftPane = dataBox, rightPane = runsListBox, split = 100, orientation = horizontal;
686 runsListBox.Update(null);
691 void NewTest(RowTests tRow, const char * testName, const char * testFilePath)
694 tRow.id = tRow.sysID;
697 tRow.filePath = testFilePath;
700 DataRow AddTest(RowTests tRow)
704 row = testListBox.AddRow();
706 s = tRow.name; row.SetData(fieldName, s); delete s;
707 row.SetData(fieldActive, tRow.active);
711 void DeleteTest(ListBox testListBox, DataRow row)
713 // do we also delete all runs and files associated with this test?
715 tRow.sysID=(uint)row.tag;
717 delete tRow; // won't be needed in the (distant?) future :-)
718 testListBox.DeleteRow(row);
726 theTestSuiteWindow.AddTest(tRow);
731 DataField fieldName { width = 140, header = "Name" , dataType = class(char*), editable = true };
732 DataField fieldActive { width = 40, header = "Active", dataType = class(bool) };
737 anchor = { top = 2, bottom = 30, left = 2, right = 2 },
740 bool NotifyChanged(ListBox testListBox, DataRow row)
743 tRow.sysID=(uint)row.tag;
744 tRow.name = row.GetData(fieldName);
745 tRow.active = row.GetData(fieldActive);
750 bool NotifyKeyDown(ListBox testListBox, DataRow row, Key key, unichar ch)
754 DeleteTest(testListBox, row);
755 // bRemove.NotifyClicked(this, bRemove,0,0,0);
757 else if(key == space)
759 //bool newActiveStatus = !(*(bool*)row.GetData(fieldActive)); // FIXME is needed?
760 row.SetData(fieldActive, !row.GetData(fieldActive));
761 testListBox.NotifyChanged(this, testListBox, row);
767 bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
772 { // print to data box
781 dataBox.Printf("Name: %s\n", tname);
782 dataBox.Printf("Location: %s\n", tpath);
783 dataBox.Printf("Active: %d\n", tactive);
784 delete tname; delete tpath;
790 runs = AccessMacros::allTestRuns(t);
795 BuildStatus buildStatus;
796 TimeStamp time = tr.time;
797 MD5Digest aura = tr.digest;
798 buildStatus = tr.makeReturnValue ? failure : success;
799 row = runsListBox.AddRow();
801 row.SetData(fieldBuildStatus, buildStatus);
802 row.SetData(fieldAuraColor, aura);
803 row.SetData(fieldRun, time);
804 row.SetData(fieldSaved, tr.save);
812 DataField fieldBuildStatus { width = 40, dataType = class(BuildStatus), header = "Make" };
813 DataField fieldAuraColor { width = 40, dataType = class(MD5Digest), header = "Aura" };
814 DataField fieldRun { width = 120, dataType = class(RelativeTimeStamp), header = "Run" };
815 DataField fieldSaved { width = 80, dataType = class(bool), header = "Save", editable = true };
821 anchor = { top = 0, bottom = 0, left = 0, right = 0 },
824 bool NotifyChanged(ListBox listBox, DataRow row)
826 TestRun tr = (TestRun)row.tag;
827 tr.save = row.GetData(fieldSaved);
837 anchor = { top = 0, bottom = 0, left = 0, right = 0 },
838 hasHorzScroll = true,
848 anchor = { bottom = 2, left = 2 };
850 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
852 FileFilter projectFilters[] =
854 { "eC project and source files (.ec, .epj)", "ec, epj" }
856 FileDialog f { filters = projectFilters, sizeFilters = sizeof(projectFilters), type = multiOpen };
862 for(i=0; i<f.numSelections; ++i)
864 char testName[MAX_LOCATION];
866 GetLastDirectory(f.multiFilePaths[i], testName);
867 NewTest(tRow, testName, f.multiFilePaths[i]);
869 if(i+1 == f.numSelections)
871 testListBox.SelectRow(row);
885 anchor = { bottom = 2, right = 2 };
887 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
890 for(row=testListBox.firstRow; row; row=row.next)
892 Test t = (Test)row.tag;
900 DateTime rightNow { };
904 runs.id = runs.sysID;
905 rightNow.GetLocalTime();
906 runs.time = (TimeStamp)rightNow;
909 bt.GenerateMakefile(t);
911 bt.AddOutputFiles(run);
920 Array<OutputFile> outputsLatest = AccessMacros::allOutputFiles(run);
921 Array<OutputFile> outputsReference = AccessMacros::allOutputFiles(t.reference);
922 dt.DiffDir(outputsReference, outputsLatest);
925 testListBox.NotifySelect(this, testListBox, testListBox.currentRow, mods);
933 text = "Accept Run (x)",
935 anchor={ bottom = 2, right = 52 };
937 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
940 MessageBox confirmation
943 text = "Accept Test",
944 contents = "Accept the selected test?"
946 if(confirmation.Modal() == yes)
949 row = runsListBox.currentRow;
952 tr = (TestRun)row.tag;
954 tr.test.reference = tr;
963 globalSettings.Load();
966 delete theGlobalSettings.diffTool;
967 theGlobalSettings.diffTool = CopyString("meld");
968 // theGlobalSettings.diffTool = CopyString("C:/Program Files/Araxis/Araxis Merge v6.5/compare.exe /wait");
973 TestSuiteWindow theTestSuiteWindow { };
974 TestSuiteGlobalSettings theGlobalSettings { };
976 class TestSuiteApp : GuiApplication
978 DataSource ds { driver = /*"SQLite" */"EDB" };
983 db = database_open(ds, "TestSuite");
987 Array<OutputFile> files;
991 RowOutputFiles rFiles { };
994 Test t = (Test)tests.id;
995 runs = AccessMacros::allTestRuns(t);
1000 if(t.reference == run)
1002 files = AccessMacros::allOutputFiles(run);
1022 settingsContainer.Load();
1023 ideConfig.compilers.read(settingsContainer);
1024 delete settingsContainer;