package gcsql import ( "database/sql/driver" "fmt" "strconv" "testing" "github.com/DATA-DOG/go-sqlmock" "github.com/gochan-org/gochan/pkg/config" "github.com/stretchr/testify/assert" ) var ( testCasesGetAppeals = []testCaseGetAppeals{ { name: "single appeal, no results", args: argsGetAppeals{1, 1}, expectReturn: nil, }, { name: "single appeal, with result", args: argsGetAppeals{1, 1}, expectReturn: []IPBanAppeal{ {ID: 1}, }, }, { name: "all appeals, no results", args: argsGetAppeals{0, 1}, expectReturn: nil, }, { name: "all appeals, with results", args: argsGetAppeals{0, 10}, expectReturn: []IPBanAppeal{{}, {}, {}}, }, } testCasesApproveAppeals = []testCaseApproveAppeals{ { name: "approve nonexistent appeal", args: argsApproveAppeal{1, 1}, }, } ) type testCaseGetAppeals struct { name string args argsGetAppeals expectReturn []IPBanAppeal } type testCaseApproveAppeals struct { name string args argsApproveAppeal } type argsGetAppeals struct { banID int limit int } type argsApproveAppeal struct { appealID int staffID int } func testRunnerGetAppeals(t *testing.T, tC *testCaseGetAppeals, driver string) { t.Helper() db, mock, err := sqlmock.New() if !assert.NoError(t, err) { return } if !assert.NoError(t, SetTestingDB(driver, "gochan", "", db)) { return } query := `SELECT id, staff_id, ip_ban_id, appeal_text, staff_response, is_denied FROM ip_ban_appeals` if tC.args.banID > 0 { switch driver { case "mysql": query += ` WHERE ip_ban_id = \?` case "sqlite3": fallthrough case "postgres": query += ` WHERE ip_ban_id = \$1` } } if tC.args.limit > 0 { query += " LIMIT " + strconv.Itoa(tC.args.limit) } expectQuery := mock.ExpectPrepare(query).ExpectQuery() if tC.args.banID > 0 { expectQuery.WithArgs(tC.args.banID) } expectedRows := sqlmock.NewRows([]string{"id", "staff_id", "ip_ban_id", "appeal_text", "staff_response", "is_denied"}) if len(tC.expectReturn) > 0 { for _, expectedBan := range tC.expectReturn { expectedRows.AddRow( expectedBan.ID, expectedBan.StaffID, expectedBan.IPBanID, expectedBan.AppealText, expectedBan.StaffResponse, expectedBan.IsDenied, ) } } expectQuery.WillReturnRows(expectedRows) got, err := GetAppeals(tC.args.banID, tC.args.limit) if !assert.NoError(t, err) { return } assert.NoError(t, mock.ExpectationsWereMet()) assert.LessOrEqual(t, len(got), tC.args.limit) assert.Equal(t, tC.expectReturn, got) if tC.args.banID > 0 && tC.expectReturn != nil { assert.Equal(t, tC.args.banID, tC.expectReturn[0].ID) } assert.NoError(t, mock.ExpectationsWereMet()) closeMock(t, mock) } func TestGetAppeals(t *testing.T) { for _, tC := range testCasesGetAppeals { for _, driver := range testingDBDrivers { t.Run(fmt.Sprintf("%s (%s)", tC.name, driver), func(t *testing.T) { config.SetTestDBConfig(driver, "localhost", "gochan", "gochan", "gochan", "") testRunnerGetAppeals(t, &tC, driver) }) } } } func testRunnerApproveAppeal(t *testing.T, tC *testCaseApproveAppeals, sqlDriver string) { t.Helper() db, mock, err := sqlmock.New() if !assert.NoError(t, err) { return } if !assert.NoError(t, SetTestingDB(sqlDriver, "gochan", "", db)) { return } deactivateQuery := `UPDATE ip_ban SET is_active = FALSE WHERE id = \(\s+` + `SELECT ip_ban_id FROM ip_ban_appeals WHERE id = ` deactivateAppealQuery := `INSERT INTO ip_ban_audit\s*\(\s*ip_ban_id, timestamp, ` + `staff_id, is_active, is_thread_ban, permanent, staff_note, message, can_appeal\)\s*VALUES\(\(` + `SELECT ip_ban_id FROM ip_ban_appeals WHERE id = ` deleteAppealQuery := `DELETE FROM ip_ban_appeals WHERE id = ` switch sqlDriver { case "mysql": deactivateQuery += `\?\)` deactivateAppealQuery += `\?\),\s*CURRENT_TIMESTAMP, \?, FALSE, FALSE, FALSE, '', '', TRUE\)` deleteAppealQuery += `\?` case "sqlite3": fallthrough case "postgres": deactivateQuery += `\$1\)` deactivateAppealQuery += `\$1\),\s+CURRENT_TIMESTAMP, \$2, FALSE, FALSE, FALSE, '', '', TRUE\)` deleteAppealQuery += `\$1` } mock.ExpectBegin() mock.ExpectPrepare(deactivateQuery).ExpectExec(). WithArgs(tC.args.appealID).WillReturnResult(driver.ResultNoRows) mock.ExpectPrepare(deactivateAppealQuery).ExpectExec(). WithArgs(tC.args.appealID, tC.args.staffID). WillReturnResult(driver.ResultNoRows) mock.ExpectPrepare(deleteAppealQuery).ExpectExec(). WithArgs(tC.args.appealID). WillReturnResult(driver.ResultNoRows) mock.ExpectCommit() assert.NoError(t, ApproveAppeal(tC.args.appealID, tC.args.staffID)) assert.NoError(t, mock.ExpectationsWereMet()) closeMock(t, mock) } func TestApproveAppeal(t *testing.T) { for _, tC := range testCasesApproveAppeals { for _, sqlDriver := range testingDBDrivers { t.Run(fmt.Sprintf("%s (%s)", tC.name, sqlDriver), func(t *testing.T) { config.SetTestDBConfig(sqlDriver, "localhost", "gochan", "gochan", "gochan", "") testRunnerApproveAppeal(t, &tC, sqlDriver) }) } } }