xj_test/src/main.cpp
2024-08-16 14:02:03 +08:00

187 lines
6.2 KiB
C++

#include "json/reader.h"
#include "json/value.h"
#include <chrono>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iostream>
#include<json/json.h>
#include <ostream>
#include <queue>
#include <sstream>
#include <string>
#include <thread>
#ifdef _WIN32
#include<windows.h>
#else
#include "unistd.h"
#endif
using std::cerr,std::endl,std::cout,std::ifstream,std::string,std::vector,std::queue,std::filesystem::path,std::thread,std::chrono::time_point,std::chrono::steady_clock,std::chrono::high_resolution_clock,std::chrono::system_clock,std::filesystem::exists;
#define AS_EQ(a,b){if((a)!=(b)){cerr<<"assert eq failed :"<<endl<<#a<<":"<<(a)<<endl<<#b<<":"<<(b)<<endl;exit(1);}}
#define AS_NE(a,b){if((a)==(b)){cerr<<"assert not eq failed :"<<endl<<#a<<":"<<(a)<<endl<<#b<<":"<<(b)<<endl;exit(1);}}
#define LOG(a){cout<<"[LOG]"<<(a)<<endl;}
#define AS_EM(a,b,m){if((a)!=(b)){cerr<<"assert eq failed :"<<endl<<#a<<":"<<(a)<<endl<<#b<<":"<<(b)<<endl<<"message:"<<(m)<<endl;exit(1);}}
#define AS_NM(a,b,m){if((a)==(b)){cerr<<"assert not eq failed :"<<endl<<#a<<":"<<(a)<<endl<<#b<<":"<<(b)<<endl<<"message:"<<(m)<<endl;exit(1);}}
#define printValue(v){cout<<#v<<":"<<(v)<<endl;}
#ifdef _WIN32
bool isWindows = true;
#else
bool isWindows=false;
#endif
#ifdef _WIN32
unsigned long getCpuNums(){
SYSTEM_INFO sysInfo;
GetSystemInfo( &sysInfo );
return sysInfo.dwNumberOfProcessors;
}
#else
unsigned long getCpuNums(){
return sysconf(_SC_NPROCESSORS_ONLN);
}
#endif
std::filesystem::path getAbsolutePath(std::filesystem::path rootPath,std::filesystem::path filePath);
string getProtectPath(const std::filesystem::path &p);
struct Test{
unsigned int id;
std::filesystem::path in;
std::filesystem::path ans;
friend std::ostream& operator<<(std::ostream& os,Test &t){
os<<"Test{"<<"in:"<<t.in<<",ans:"<<t.ans<<"} ";
return os;
}
};
struct ProgramRet{
time_point<system_clock> start;
time_point<system_clock> end;
};
template<typename T>
T getValueOrPanic(T value);
int main(int argc, char* argv[]) {
LOG("Zengtudor OI test tools . loading files .. please add a json file in arg");
printValue(argv[0])
AS_EQ(argc,2)
std::filesystem::path jsonPath(argv[1]);
if (!jsonPath.is_absolute()) {
LOG("The path is not absolute, changing it")
jsonPath = std::filesystem::current_path()/jsonPath;
}
LOG("getting json files current dir")
LOG(jsonPath)
AS_EM(std::filesystem::exists(jsonPath), true, "Please create the json file,the json file was not exist")
LOG("getting project path")
const auto projectPath = jsonPath.parent_path();
LOG(projectPath)
LOG("will use g++ compiler")
LOG("checking g++ compiler version")
int sys_ret = system("g++ --version");
AS_EM(sys_ret,0,"get g++ --version failed")
const auto buildDir = projectPath / "build";
LOG("getting build dir")
LOG(buildDir)
LOG("parsing json file")
ifstream jsonFileStream(jsonPath);
Json::Value jsonValue;
Json::Reader jsonReader;
jsonReader.parse(jsonFileStream,jsonValue);
AS_NM(jsonValue["files"], Json::nullValue, "cannot read the json value `files` array")
string projectFilesBuildString;
LOG("parsing files in json values")
for(auto i:jsonValue["files"]){
projectFilesBuildString = projectFilesBuildString + " " +getProtectPath(getAbsolutePath(projectPath, std::filesystem::path(i.asString())));
}
printValue(projectFilesBuildString)
LOG("parsing g++ compiler args")
string compileArgs;
for(auto i:jsonValue["args"]){
compileArgs = compileArgs + " "+i.asString();
}
printValue(compileArgs)
if(std::filesystem::exists(buildDir)==false){
LOG("creating building dir")
std::filesystem::create_directory(buildDir);
}
LOG("compiling")
string compileCommands;
const path exePath = (buildDir/"main").string()+(isWindows==true?".exe":"");
printValue(exePath)
compileCommands=compileCommands+"g++ "+"-o "+getProtectPath(exePath)+" "+projectFilesBuildString+" "+compileArgs;
printValue(compileCommands)
AS_EM(system(compileCommands.c_str()), 0, "compile the program failed")
auto cpuNums = getCpuNums();
printValue(cpuNums)
if(jsonValue["tests"].size()==0)LOG("cannot find tests");
LOG("parsing tests")
vector<Test> tests;
auto &jsonTests = jsonValue["tests"];
for(unsigned int i=1;i<=jsonTests.size();i++){
tests.push_back({
.id = i,
.in=getAbsolutePath(projectPath, getValueOrPanic(jsonTests[i-1]["in"]).asString()),
.ans=getAbsolutePath(projectPath,getValueOrPanic(jsonTests[i-1]["ans"]).asString()),
});
}
queue<std::function<ProgramRet()>> tasks;
const auto testsPath = projectPath/"tests";
if(!exists(testsPath)){
LOG("creating the test dir")
std::filesystem::create_directory(testsPath);
}
printValue(testsPath)
const string exePathStr = getProtectPath(exePath);
for(auto i:tests){
tasks.push([i,&exePathStr,&testsPath]()->ProgramRet{
string commands;
std::stringstream ss;
ss<<i.id;
string id_str;
ss>>id_str;
path outPath = testsPath/(id_str+".out") ;
commands = commands+exePathStr+" < "+getProtectPath(i.in)+" > "+getProtectPath(outPath);
LOG(commands)
auto start = high_resolution_clock::now();
system(commands.c_str());
auto end=high_resolution_clock::now();
return ProgramRet{
.start=start,
.end = end
};
});
}
while(tasks.size()>0){
auto i = tasks.front();
tasks.pop();
thread newThread(i);
AS_EQ(newThread.joinable(),true);
newThread.join();
}
}
string getProtectPath(const std::filesystem::path &p){
return "\""+p.string()+"\"";
}
template<typename T>
T getValueOrPanic(T value){
AS_NE(value, Json::nullValue)
return value;
}
std::filesystem::path getAbsolutePath(std::filesystem::path rootPath,std::filesystem::path filePath){
if(filePath.is_absolute()==false){
filePath = rootPath/filePath;
}
return filePath;
}