diff --git a/tests/phpunit/tests/comment-submission.php b/tests/phpunit/tests/comment-submission.php
new file mode 100644
index 0000000000..cbf0125f97
--- /dev/null
+++ b/tests/phpunit/tests/comment-submission.php
@@ -0,0 +1,540 @@
+assertSame( 0, did_action( $error ) );
+
+ $data = array(
+ 'comment_post_ID' => 0,
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertSame( 1, did_action( $error ) );
+ $this->assertWPError( $comment );
+ $this->assertSame( $error, $comment->get_error_code() );
+
+ }
+
+ public function test_submitting_comment_to_post_with_closed_comments_returns_error() {
+
+ $error = 'comment_closed';
+
+ $this->assertSame( 0, did_action( $error ) );
+
+ $post = $this->factory->post->create_and_get( array(
+ 'comment_status' => 'closed',
+ ) );
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertSame( 1, did_action( $error ) );
+ $this->assertWPError( $comment );
+ $this->assertSame( $error, $comment->get_error_code() );
+
+ }
+
+ public function test_submitting_comment_to_trashed_post_returns_error() {
+
+ $error = 'comment_on_trash';
+
+ $this->assertSame( 0, did_action( $error ) );
+
+ $post = $this->factory->post->create_and_get();
+ wp_trash_post( $post );
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertSame( 1, did_action( $error ) );
+ $this->assertWPError( $comment );
+ $this->assertSame( $error, $comment->get_error_code() );
+
+ }
+
+ public function test_submitting_comment_to_draft_post_returns_error() {
+
+ $error = 'comment_on_draft';
+
+ $this->assertSame( 0, did_action( $error ) );
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_status' => 'draft',
+ ) );
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertSame( 1, did_action( $error ) );
+ $this->assertWPError( $comment );
+ $this->assertSame( $error, $comment->get_error_code() );
+
+ }
+
+ public function test_submitting_comment_to_scheduled_post_returns_error() {
+
+ // Same error as commenting on a draft
+ $error = 'comment_on_draft';
+
+ $this->assertSame( 0, did_action( $error ) );
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_date' => date( 'Y-m-d H:i:s', strtotime( '+1 day' ) ),
+ ) );
+
+ $this->assertSame( 'future', $post->post_status );
+
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertSame( 1, did_action( $error ) );
+ $this->assertWPError( $comment );
+ $this->assertSame( $error, $comment->get_error_code() );
+
+ }
+
+ public function test_submitting_comment_to_password_required_post_returns_error() {
+
+ $error = 'comment_on_password_protected';
+
+ $this->assertSame( 0, did_action( $error ) );
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_password' => 'password',
+ ) );
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertSame( 1, did_action( $error ) );
+ $this->assertWPError( $comment );
+ $this->assertSame( $error, $comment->get_error_code() );
+
+ }
+
+ public function test_submitting_comment_to_password_protected_post_succeeds() {
+
+ $password = 'password';
+ $hasher = new PasswordHash( 8, true );
+
+ $_COOKIE['wp-postpass_' . COOKIEHASH] = $hasher->HashPassword( $password );
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_password' => $password,
+ ) );
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ 'comment' => 'Comment',
+ 'author' => 'Comment Author',
+ 'email' => 'comment@example.org',
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ unset( $_COOKIE['wp-postpass_' . COOKIEHASH] );
+
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+
+ }
+
+ public function test_submitting_valid_comment_as_logged_in_user_succeeds() {
+
+ $user = $this->factory->user->create_and_get( array(
+ 'user_url' => 'http://user.example.org'
+ ) );
+
+ wp_set_current_user( $user->ID );
+
+ $post = $this->factory->post->create_and_get();
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ 'comment' => 'Comment',
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+
+ $this->assertSame( 'Comment', $comment->comment_content);
+ $this->assertSame( $user->display_name, $comment->comment_author );
+ $this->assertSame( $user->user_email, $comment->comment_author_email );
+ $this->assertSame( $user->user_url, $comment->comment_author_url );
+
+ }
+
+ public function test_submitting_valid_comment_anonymously_succeeds() {
+
+ $post = $this->factory->post->create_and_get();
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ 'comment' => 'Comment',
+ 'author' => 'Comment Author',
+ 'email' => 'comment@example.org',
+ 'url' => 'user.example.org'
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+
+ $this->assertSame( 'Comment', $comment->comment_content);
+ $this->assertSame( 'Comment Author', $comment->comment_author );
+ $this->assertSame( 'comment@example.org', $comment->comment_author_email );
+ $this->assertSame( 'http://user.example.org', $comment->comment_author_url );
+
+ }
+
+ /**
+ * wp_handle_comment_submission() expects un-slashed data.
+ *
+ * @group slashes
+ */
+ public function test_submitting_comment_handles_slashes_correctly_handles_slashes() {
+
+ $post = $this->factory->post->create_and_get();
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ 'comment' => 'Comment with 1 slash: \\',
+ 'author' => 'Comment Author with 1 slash: \\',
+ 'email' => 'comment@example.org',
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+
+ $this->assertSame( 'Comment with 1 slash: \\', $comment->comment_content);
+ $this->assertSame( 'Comment Author with 1 slash: \\', $comment->comment_author );
+ $this->assertSame( 'comment@example.org', $comment->comment_author_email );
+
+ }
+
+ public function test_submitting_comment_anonymously_to_private_post_returns_error() {
+
+ $error = 'not_logged_in';
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_status' => 'private',
+ ) );
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertFalse( is_user_logged_in() );
+ $this->assertWPError( $comment );
+ $this->assertSame( $error, $comment->get_error_code() );
+
+ }
+
+ public function test_submitting_comment_to_own_private_post_succeeds() {
+
+ $user = $this->factory->user->create_and_get();
+
+ wp_set_current_user( $user->ID );
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_status' => 'private',
+ 'post_author' => $user->ID,
+ ) );
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ 'comment' => 'Comment',
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertTrue( current_user_can( 'read_post', $post->ID ) );
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+
+ }
+
+ public function test_submitting_comment_to_accessible_private_post_succeeds() {
+
+ $author = $this->factory->user->create_and_get( array(
+ 'role' => 'author',
+ ) );
+ $user = $this->factory->user->create_and_get( array(
+ 'role' => 'editor',
+ ) );
+
+ wp_set_current_user( $user->ID );
+
+ $post = $this->factory->post->create_and_get( array(
+ 'post_status' => 'private',
+ 'post_author' => $author->ID,
+ ) );
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ 'comment' => 'Comment',
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertTrue( current_user_can( 'read_post', $post->ID ) );
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+
+ }
+
+ public function test_anonymous_user_cannot_comment_unfiltered_html() {
+
+ $post = $this->factory->post->create_and_get();
+ $data = array(
+ 'comment_post_ID' => $post->ID,
+ 'comment' => 'Comment ',
+ 'author' => 'Comment Author',
+ 'email' => 'comment@example.org',
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+ $this->assertNotContains( '',
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+ $this->assertNotContains( '',
+ '_wp_unfiltered_html_comment' => $nonce,
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+ $this->assertNotContains( '',
+ '_wp_unfiltered_html_comment' => $nonce,
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+ $this->assertContains( '',
+ );
+ $comment = wp_handle_comment_submission( $data );
+
+ $this->assertNotWPError( $comment );
+ $this->assertInstanceOf( 'WP_Comment', $comment );
+ $this->assertNotContains( '