package log import ( "fmt" "strings" "testing" "github.com/DATA-DOG/go-sqlmock" "gorm.io/driver/mysql" "gorm.io/gorm" ) func TestHasRefundCommissionLog(t *testing.T) { const orderNo = "ORD-REFUND-1" t.Run("returns true when 333 log exists for the order", func(t *testing.T) { db, mock, cleanup := newRefundLogTestDB(t) defer cleanup() mock.ExpectQuery("FROM `system_logs`"). WithArgs(uint8(33), fmt.Sprintf(`%%"order_no":"%s"%%`, orderNo)). WillReturnRows(sqlmock.NewRows([]string{"id", "content"}). AddRow(1, fmt.Sprintf(`{"type":331,"order_no":"%s","amount":100}`, orderNo)). AddRow(2, fmt.Sprintf(`{"type":333,"order_no":"%s","amount":-100}`, orderNo))) got, err := HasRefundCommissionLog(db, orderNo) if err != nil { t.Fatalf("HasRefundCommissionLog error: %v", err) } if !got { t.Fatalf("HasRefundCommissionLog = false, want true") } assertRefundLogExpectations(t, mock) }) t.Run("returns false when only 331/332 logs exist", func(t *testing.T) { db, mock, cleanup := newRefundLogTestDB(t) defer cleanup() mock.ExpectQuery("FROM `system_logs`"). WithArgs(uint8(33), fmt.Sprintf(`%%"order_no":"%s"%%`, orderNo)). WillReturnRows(sqlmock.NewRows([]string{"id", "content"}). AddRow(1, fmt.Sprintf(`{"type":331,"order_no":"%s","amount":100}`, orderNo)). AddRow(2, fmt.Sprintf(`{"type":332,"order_no":"%s","amount":50}`, orderNo))) got, err := HasRefundCommissionLog(db, orderNo) if err != nil { t.Fatalf("HasRefundCommissionLog error: %v", err) } if got { t.Fatalf("HasRefundCommissionLog = true, want false") } assertRefundLogExpectations(t, mock) }) t.Run("returns false when no log exists for the order", func(t *testing.T) { db, mock, cleanup := newRefundLogTestDB(t) defer cleanup() mock.ExpectQuery("FROM `system_logs`"). WithArgs(uint8(33), fmt.Sprintf(`%%"order_no":"%s"%%`, orderNo)). WillReturnRows(sqlmock.NewRows([]string{"id", "content"})) got, err := HasRefundCommissionLog(db, orderNo) if err != nil { t.Fatalf("HasRefundCommissionLog error: %v", err) } if got { t.Fatalf("HasRefundCommissionLog = true, want false") } assertRefundLogExpectations(t, mock) }) t.Run("returns false for empty order_no without querying", func(t *testing.T) { db, mock, cleanup := newRefundLogTestDB(t) defer cleanup() got, err := HasRefundCommissionLog(db, "") if err != nil { t.Fatalf("HasRefundCommissionLog error: %v", err) } if got { t.Fatalf("HasRefundCommissionLog = true, want false") } assertRefundLogExpectations(t, mock) }) t.Run("ignores 333 log when order_no in content does not match", func(t *testing.T) { // Defensive: LIKE pattern may match a substring; JSON match catches it. db, mock, cleanup := newRefundLogTestDB(t) defer cleanup() mock.ExpectQuery("FROM `system_logs`"). WithArgs(uint8(33), fmt.Sprintf(`%%"order_no":"%s"%%`, orderNo)). WillReturnRows(sqlmock.NewRows([]string{"id", "content"}). AddRow(1, `{"type":333,"order_no":"OTHER","amount":-100}`)) got, err := HasRefundCommissionLog(db, orderNo) if err != nil { t.Fatalf("HasRefundCommissionLog error: %v", err) } if got { t.Fatalf("HasRefundCommissionLog = true, want false (different order_no)") } assertRefundLogExpectations(t, mock) }) t.Run("ignores malformed json content", func(t *testing.T) { db, mock, cleanup := newRefundLogTestDB(t) defer cleanup() mock.ExpectQuery("FROM `system_logs`"). WithArgs(uint8(33), fmt.Sprintf(`%%"order_no":"%s"%%`, orderNo)). WillReturnRows(sqlmock.NewRows([]string{"id", "content"}). AddRow(1, `not a json`). AddRow(2, fmt.Sprintf(`{"type":333,"order_no":"%s","amount":-100}`, orderNo))) got, err := HasRefundCommissionLog(db, orderNo) if err != nil { t.Fatalf("HasRefundCommissionLog error: %v", err) } if !got { t.Fatalf("HasRefundCommissionLog = false, want true") } assertRefundLogExpectations(t, mock) }) t.Run("returns error when db query fails", func(t *testing.T) { db, mock, cleanup := newRefundLogTestDB(t) defer cleanup() mock.ExpectQuery("FROM `system_logs`"). WithArgs(uint8(33), fmt.Sprintf(`%%"order_no":"%s"%%`, orderNo)). WillReturnError(fmt.Errorf("connection lost")) if _, err := HasRefundCommissionLog(db, orderNo); err == nil { t.Fatalf("expected error, got nil") } assertRefundLogExpectations(t, mock) }) } func newRefundLogTestDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock, func()) { t.Helper() sqlDB, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherFunc(func(expectedSQL, actualSQL string) error { if strings.Contains(actualSQL, expectedSQL) { return nil } return fmt.Errorf("actual sql %q does not contain %q", actualSQL, expectedSQL) }))) if err != nil { t.Fatalf("create sqlmock: %v", err) } db, err := gorm.Open(mysql.New(mysql.Config{Conn: sqlDB, SkipInitializeWithVersion: true}), &gorm.Config{}) if err != nil { _ = sqlDB.Close() t.Fatalf("open gorm db: %v", err) } return db, mock, func() { _ = sqlDB.Close() } } func assertRefundLogExpectations(t *testing.T, mock sqlmock.Sqlmock) { t.Helper() if err := mock.ExpectationsWereMet(); err != nil { t.Fatalf("unmet sql expectations: %v", err) } }