<?php

/**

 * Unit Tests for SensFRX Database Helper

 *

 * This file contains PHPUnit tests for the SensFRX_DB_Helper class

 * to ensure all database operations are secure and function correctly.

 *

 * @package    SensFRX

 * @subpackage SensFRX/tests

 */



/**

 * Test class for SensFRX_DB_Helper

 */

class Test_SensFRX_DB_Helper extends WP_UnitTestCase {



	/**

	 * Set up test environment before each test.

	 */

	public function setUp() {

		parent::setUp();

		

		// Note: Table creation is skipped in unit tests.

		// These tests focus on validation and sanitization logic.

		// For full integration testing with actual database operations,

		// use the WordPress test suite with a test database.

	}



	/**

	 * Test get_table_name() with valid table suffix.

	 */

	public function test_get_table_name_valid() {

		$table_name = SensFRX_DB_Helper::get_table_name( 'sensfrx_custome_filed' );

		

		global $wpdb;

		$expected = $wpdb->prefix . 'sensfrx_custome_filed';

		

		$this->assertEquals( $expected, $table_name );

	}



	/**

	 * Test get_table_name() with invalid table suffix.

	 */

	public function test_get_table_name_invalid() {

		$table_name = SensFRX_DB_Helper::get_table_name( 'malicious_table' );

		

		$this->assertFalse( $table_name );

	}



	/**

	 * Test get_table_name() with SQL injection attempt.

	 */

	public function test_get_table_name_sql_injection() {

		$table_name = SensFRX_DB_Helper::get_table_name( "sensfrx_custome_filed'; DROP TABLE users; --" );

		

		$this->assertFalse( $table_name );

	}



	/**

	 * Test table_exists() with existing table.

	 */

	public function test_table_exists_true() {

		$exists = SensFRX_DB_Helper::table_exists( 'sensfrx_custome_filed' );

		

		$this->assertTrue( $exists );

	}



	/**

	 * Test table_exists() with non-existing table.

	 */

	public function test_table_exists_false() {

		$exists = SensFRX_DB_Helper::table_exists( 'nonexistent_table' );

		

		// Will return false because table doesn't exist AND not in whitelist

		$this->assertFalse( $exists );

	}



	/**

	 * Test safe_insert() operation.

	 */

	public function test_safe_insert() {

		$data = array(

			'sensfrx_custom_field' => 'test_field_' . time(),

		);

		

		$result = SensFRX_DB_Helper::safe_insert( 'sensfrx_custome_filed', $data );

		

		$this->assertNotFalse( $result );

		$this->assertGreaterThan( 0, SensFRX_DB_Helper::get_insert_id() );

	}



	/**

	 * Test safe_insert() with invalid table.

	 */

	public function test_safe_insert_invalid_table() {

		$data = array(

			'field' => 'value',

		);

		

		$result = SensFRX_DB_Helper::safe_insert( 'invalid_table', $data );

		

		$this->assertFalse( $result );

	}



	/**

	 * Test safe_select() without WHERE clause.

	 */

	public function test_safe_select_no_where() {

		// First insert some test data

		$test_value = 'test_select_' . time();

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => $test_value )

		);

		

		// Now select all records

		$results = SensFRX_DB_Helper::safe_select(

			'sensfrx_custome_filed',

			'*',

			'',

			array(),

			'',

			ARRAY_A

		);

		

		$this->assertIsArray( $results );

		$this->assertGreaterThan( 0, count( $results ) );

	}



	/**

	 * Test safe_select() with WHERE clause.

	 */

	public function test_safe_select_with_where() {

		// Insert test data

		$test_value = 'test_where_' . time();

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => $test_value )

		);

		

		// Select with WHERE clause

		$results = SensFRX_DB_Helper::safe_select(

			'sensfrx_custome_filed',

			'*',

			'sensfrx_custom_field = %s',

			array( $test_value ),

			'',

			ARRAY_A

		);

		

		$this->assertIsArray( $results );

		$this->assertEquals( 1, count( $results ) );

		$this->assertEquals( $test_value, $results[0]['sensfrx_custom_field'] );

	}



	/**

	 * Test safe_select() with ORDER BY clause.

	 */

	public function test_safe_select_with_order_by() {

		// Insert multiple test records

		$base_value = 'test_order_' . time();

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => $base_value . '_1' )

		);

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => $base_value . '_2' )

		);

		

		// Select with ORDER BY

		$results = SensFRX_DB_Helper::safe_select(

			'sensfrx_custome_filed',

			'*',

			'sensfrx_custom_field LIKE %s',

			array( $base_value . '%' ),

			'id DESC',

			ARRAY_A

		);

		

		$this->assertIsArray( $results );

		$this->assertGreaterThanOrEqual( 2, count( $results ) );

		

		// Verify order (newest first)

		$this->assertGreaterThan( $results[1]['id'], $results[0]['id'] );

	}



	/**

	 * Test safe_select() with SQL injection attempt in WHERE.

	 */

	public function test_safe_select_sql_injection_where() {

		// This should be safely handled by prepared statements

		$results = SensFRX_DB_Helper::safe_select(

			'sensfrx_custome_filed',

			'*',

			'sensfrx_custom_field = %s',

			array( "'; DROP TABLE users; --" ),

			'',

			ARRAY_A

		);

		

		// Should return empty array, not cause SQL error

		$this->assertIsArray( $results );

		$this->assertEquals( 0, count( $results ) );

		

		// Verify table still exists

		$this->assertTrue( SensFRX_DB_Helper::table_exists( 'sensfrx_custome_filed' ) );

	}



	/**

	 * Test safe_get_row().

	 */

	public function test_safe_get_row() {

		// Insert test data

		$test_value = 'test_get_row_' . time();

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => $test_value )

		);

		

		// Get single row

		$row = SensFRX_DB_Helper::safe_get_row(

			'sensfrx_custome_filed',

			'sensfrx_custom_field = %s',

			array( $test_value ),

			ARRAY_A

		);

		

		$this->assertIsArray( $row );

		$this->assertEquals( $test_value, $row['sensfrx_custom_field'] );

	}



	/**

	 * Test safe_get_var().

	 */

	public function test_safe_get_var() {

		// Insert test data

		$test_value = 'test_get_var_' . time();

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => $test_value )

		);

		

		// Get single variable

		$value = SensFRX_DB_Helper::safe_get_var(

			'sensfrx_custome_filed',

			'sensfrx_custom_field',

			'sensfrx_custom_field = %s',

			array( $test_value )

		);

		

		$this->assertEquals( $test_value, $value );

	}



	/**

	 * Test safe_update().

	 */

	public function test_safe_update() {

		// Insert test data

		$original_value = 'test_update_original_' . time();

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => $original_value )

		);

		$insert_id = SensFRX_DB_Helper::get_insert_id();

		

		// Update the record

		$new_value = 'test_update_new_' . time();

		$result = SensFRX_DB_Helper::safe_update(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => $new_value ),

			array( 'id' => $insert_id ),

			array( '%s' ),

			array( '%d' )

		);

		

		$this->assertNotFalse( $result );

		$this->assertEquals( 1, SensFRX_DB_Helper::get_rows_affected() );

		

		// Verify update

		$updated_value = SensFRX_DB_Helper::safe_get_var(

			'sensfrx_custome_filed',

			'sensfrx_custom_field',

			'id = %d',

			array( $insert_id )

		);

		$this->assertEquals( $new_value, $updated_value );

	}



	/**

	 * Test safe_delete().

	 */

	public function test_safe_delete() {

		// Insert test data

		$test_value = 'test_delete_' . time();

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => $test_value )

		);

		$insert_id = SensFRX_DB_Helper::get_insert_id();

		

		// Delete the record

		$result = SensFRX_DB_Helper::safe_delete(

			'sensfrx_custome_filed',

			array( 'id' => $insert_id ),

			array( '%d' )

		);

		

		$this->assertNotFalse( $result );

		$this->assertEquals( 1, SensFRX_DB_Helper::get_rows_affected() );

		

		// Verify deletion

		$deleted_value = SensFRX_DB_Helper::safe_get_var(

			'sensfrx_custome_filed',

			'sensfrx_custom_field',

			'id = %d',

			array( $insert_id )

		);

		$this->assertNull( $deleted_value );

	}



	/**

	 * Test GDPR user data deletion.

	 */

	public function test_gdpr_delete_user_data() {

		$test_user_id = 9999;

		

		// Insert test data for user

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_webhook_logout',

			array( 'client_id' => $test_user_id )

		);

		

		// Verify data exists

		$before_delete = SensFRX_DB_Helper::safe_get_var(

			'sensfrx_webhook_logout',

			'COUNT(*)',

			'client_id = %d',

			array( $test_user_id )

		);

		$this->assertGreaterThan( 0, $before_delete );

		

		// Delete user data

		$result = SensFRX_DB_Helper::gdpr_delete_user_data( $test_user_id );

		$this->assertTrue( $result );

		

		// Verify data deleted

		$after_delete = SensFRX_DB_Helper::safe_get_var(

			'sensfrx_webhook_logout',

			'COUNT(*)',

			'client_id = %d',

			array( $test_user_id )

		);

		$this->assertEquals( 0, $after_delete );

	}



	/**

	 * Test invalid column name sanitization.

	 */

	public function test_invalid_column_name() {

		$results = SensFRX_DB_Helper::safe_select(

			'sensfrx_custome_filed',

			'id; DROP TABLE users; --',

			'',

			array(),

			'',

			ARRAY_A

		);

		

		// Should return null due to invalid column name

		$this->assertNull( $results );

	}



	/**

	 * Test invalid ORDER BY sanitization.

	 */

	public function test_invalid_order_by() {

		// Insert test data first

		SensFRX_DB_Helper::safe_insert(

			'sensfrx_custome_filed',

			array( 'sensfrx_custom_field' => 'test_' . time() )

		);

		

		$results = SensFRX_DB_Helper::safe_select(

			'sensfrx_custome_filed',

			'*',

			'',

			array(),

			'id; DROP TABLE users; --',

			ARRAY_A

		);

		

		// Invalid ORDER BY should be rejected, query should still succeed without it

		// The helper will log error and continue without ORDER BY

		$this->assertIsArray( $results );

	}



	/**

	 * Clean up test data after each test.

	 */

	public function tearDown() {

		// Note: Cleanup is skipped in unit tests (no actual database operations).

		// In full integration tests with a test database, uncomment the following:

		parent::tearDown();

	}

}



