package sqlmock import ( "database/sql" "fmt" "testing" ) func ExampleRows() { db, mock, err := New() if err != nil { fmt.Println("failed to open sqlmock database:", err) } defer db.Close() rows := NewRows([]string{"id", "title"}). AddRow(1, "one"). AddRow(2, "two") mock.ExpectQuery("SELECT").WillReturnRows(rows) rs, _ := db.Query("SELECT") defer rs.Close() for rs.Next() { var id int var title string rs.Scan(&id, &title) fmt.Println("scanned id:", id, "and title:", title) } if rs.Err() != nil { fmt.Println("got rows error:", rs.Err()) } // Output: scanned id: 1 and title: one // scanned id: 2 and title: two } func ExampleRows_rowError() { db, mock, err := New() if err != nil { fmt.Println("failed to open sqlmock database:", err) } defer db.Close() rows := NewRows([]string{"id", "title"}). AddRow(0, "one"). AddRow(1, "two"). RowError(1, fmt.Errorf("row error")) mock.ExpectQuery("SELECT").WillReturnRows(rows) rs, _ := db.Query("SELECT") defer rs.Close() for rs.Next() { var id int var title string rs.Scan(&id, &title) fmt.Println("scanned id:", id, "and title:", title) } if rs.Err() != nil { fmt.Println("got rows error:", rs.Err()) } // Output: scanned id: 0 and title: one // got rows error: row error } func ExampleRows_closeError() { db, mock, err := New() if err != nil { fmt.Println("failed to open sqlmock database:", err) } defer db.Close() rows := NewRows([]string{"id", "title"}).CloseError(fmt.Errorf("close error")) mock.ExpectQuery("SELECT").WillReturnRows(rows) rs, _ := db.Query("SELECT") // Note: that close will return error only before rows EOF // that is a default sql package behavior. If you run rs.Next() // it will handle the error internally and return nil bellow if err := rs.Close(); err != nil { fmt.Println("got error:", err) } // Output: got error: close error } func TestAllowsToSetRowsErrors(t *testing.T) { t.Parallel() db, mock, err := New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() rows := NewRows([]string{"id", "title"}). AddRow(0, "one"). AddRow(1, "two"). RowError(1, fmt.Errorf("error")) mock.ExpectQuery("SELECT").WillReturnRows(rows) rs, err := db.Query("SELECT") if err != nil { t.Fatalf("unexpected error: %s", err) } defer rs.Close() if !rs.Next() { t.Fatal("expected the first row to be available") } if rs.Err() != nil { t.Fatalf("unexpected error: %s", rs.Err()) } if rs.Next() { t.Fatal("was not expecting the second row, since there should be an error") } if rs.Err() == nil { t.Fatal("expected an error, but got none") } if err := mock.ExpectationsWereMet(); err != nil { t.Fatal(err) } } func TestRowsCloseError(t *testing.T) { t.Parallel() db, mock, err := New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() rows := NewRows([]string{"id"}).CloseError(fmt.Errorf("close error")) mock.ExpectQuery("SELECT").WillReturnRows(rows) rs, err := db.Query("SELECT") if err != nil { t.Fatalf("unexpected error: %s", err) } if err := rs.Close(); err == nil { t.Fatal("expected a close error") } if err := mock.ExpectationsWereMet(); err != nil { t.Fatal(err) } } func TestQuerySingleRow(t *testing.T) { t.Parallel() db, mock, err := New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() rows := NewRows([]string{"id"}). AddRow(1). AddRow(2) mock.ExpectQuery("SELECT").WillReturnRows(rows) var id int if err := db.QueryRow("SELECT").Scan(&id); err != nil { t.Fatalf("unexpected error: %s", err) } mock.ExpectQuery("SELECT").WillReturnRows(NewRows([]string{"id"})) if err := db.QueryRow("SELECT").Scan(&id); err != sql.ErrNoRows { t.Fatal("expected sql no rows error") } if err := mock.ExpectationsWereMet(); err != nil { t.Fatal(err) } } func TestRowsScanError(t *testing.T) { t.Parallel() db, mock, err := New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() r := NewRows([]string{"col1", "col2"}).AddRow("one", "two").AddRow("one", nil) mock.ExpectQuery("SELECT").WillReturnRows(r) rs, err := db.Query("SELECT") if err != nil { t.Fatalf("unexpected error: %s", err) } defer rs.Close() var one, two string if !rs.Next() || rs.Err() != nil || rs.Scan(&one, &two) != nil { t.Fatal("unexpected error on first row scan") } if !rs.Next() || rs.Err() != nil { t.Fatal("unexpected error on second row read") } err = rs.Scan(&one, &two) if err == nil { t.Fatal("expected an error for scan, but got none") } if err := mock.ExpectationsWereMet(); err != nil { t.Fatal(err) } } func TestCSVRowParser(t *testing.T) { t.Parallel() rs := NewRows([]string{"col1", "col2"}).FromCSVString("a,NULL") db, mock, err := New() if err != nil { t.Fatalf("an error '%s' was not expected when opening a stub database connection", err) } defer db.Close() mock.ExpectQuery("SELECT").WillReturnRows(rs) rw, err := db.Query("SELECT") if err != nil { t.Fatalf("unexpected error: %s", err) } defer rw.Close() var col1 string var col2 []byte rw.Next() if err = rw.Scan(&col1, &col2); err != nil { t.Fatalf("unexpected error: %s", err) } if col1 != "a" { t.Fatalf("expected col1 to be 'a', but got [%T]:%+v", col1, col1) } if col2 != nil { t.Fatalf("expected col2 to be nil, but got [%T]:%+v", col2, col2) } }