feat: rebuild CSP practice workflow, UX and automation
这个提交包含在:
@@ -0,0 +1,89 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "csp/app_state.h"
|
||||
#include "csp/controllers/problem_controller.h"
|
||||
#include "csp/services/auth_service.h"
|
||||
|
||||
#include <drogon/HttpRequest.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <future>
|
||||
|
||||
namespace {
|
||||
|
||||
int64_t FirstProblemId() {
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
auto* db = csp::AppState::Instance().db().raw();
|
||||
REQUIRE(sqlite3_prepare_v2(db, "SELECT id FROM problems ORDER BY id LIMIT 1", -1,
|
||||
&stmt, nullptr) == SQLITE_OK);
|
||||
REQUIRE(sqlite3_step(stmt) == SQLITE_ROW);
|
||||
const auto id = sqlite3_column_int64(stmt, 0);
|
||||
sqlite3_finalize(stmt);
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string NewToken() {
|
||||
csp::services::AuthService auth(csp::AppState::Instance().db());
|
||||
const auto r = auth.Register("workspace_tester", "password123");
|
||||
return r.token;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("problem controller draft and solution list") {
|
||||
csp::AppState::Instance().Init(":memory:");
|
||||
csp::controllers::ProblemController ctl;
|
||||
|
||||
const auto problem_id = FirstProblemId();
|
||||
const auto token = NewToken();
|
||||
|
||||
{
|
||||
Json::Value body;
|
||||
body["language"] = "cpp";
|
||||
body["code"] = "int main(){return 0;}";
|
||||
body["stdin"] = "1 2\n";
|
||||
|
||||
auto req = drogon::HttpRequest::newHttpJsonRequest(body);
|
||||
req->setMethod(drogon::Put);
|
||||
req->addHeader("Authorization", "Bearer " + token);
|
||||
|
||||
std::promise<drogon::HttpResponsePtr> p;
|
||||
ctl.saveDraft(req,
|
||||
[&p](const drogon::HttpResponsePtr& resp) { p.set_value(resp); },
|
||||
problem_id);
|
||||
auto resp = p.get_future().get();
|
||||
REQUIRE(resp->statusCode() == drogon::k200OK);
|
||||
}
|
||||
|
||||
{
|
||||
auto req = drogon::HttpRequest::newHttpRequest();
|
||||
req->setMethod(drogon::Get);
|
||||
req->addHeader("Authorization", "Bearer " + token);
|
||||
|
||||
std::promise<drogon::HttpResponsePtr> p;
|
||||
ctl.getDraft(req,
|
||||
[&p](const drogon::HttpResponsePtr& resp) { p.set_value(resp); },
|
||||
problem_id);
|
||||
auto resp = p.get_future().get();
|
||||
REQUIRE(resp->statusCode() == drogon::k200OK);
|
||||
auto json = resp->jsonObject();
|
||||
REQUIRE(json != nullptr);
|
||||
REQUIRE((*json)["data"]["code"].asString().find("main") != std::string::npos);
|
||||
}
|
||||
|
||||
{
|
||||
auto req = drogon::HttpRequest::newHttpRequest();
|
||||
req->setMethod(drogon::Get);
|
||||
|
||||
std::promise<drogon::HttpResponsePtr> p;
|
||||
ctl.listSolutions(
|
||||
req,
|
||||
[&p](const drogon::HttpResponsePtr& resp) { p.set_value(resp); },
|
||||
problem_id);
|
||||
auto resp = p.get_future().get();
|
||||
REQUIRE(resp->statusCode() == drogon::k200OK);
|
||||
auto json = resp->jsonObject();
|
||||
REQUIRE(json != nullptr);
|
||||
REQUIRE((*json)["data"]["items"].isArray());
|
||||
}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户