Skip to content

Commit

Permalink
Merge branch 'creme332:main' into useenum
Browse files Browse the repository at this point in the history
  • Loading branch information
Divyeshhhh authored Jun 12, 2024
2 parents 2f796ce + 0215865 commit 4a263d4
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 75 deletions.
8 changes: 4 additions & 4 deletions resources/database/cafe_schema.sql
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-- MySQL dump 10.19 Distrib 10.3.38-MariaDB, for debian-linux-gnu (x86_64)
-- MySQL dump 10.19 Distrib 10.3.39-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database: cafe
-- ------------------------------------------------------
-- Server version 10.3.38-MariaDB-0ubuntu0.20.04.1
-- Server version 10.3.39-MariaDB-0ubuntu0.20.04.2

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
Expand Down Expand Up @@ -79,7 +79,7 @@ CREATE TABLE `comment` (
KEY `comment_comment_comment_id_fk` (`parent_comment_id`),
KEY `comment_user_user_id_fk` (`user_id`),
KEY `comment_review_review_id_fk` (`review_id`),
CONSTRAINT `comment_comment_comment_id_fk` FOREIGN KEY (`parent_comment_id`) REFERENCES `comment` (`comment_id`),
CONSTRAINT `comment_comment_comment_id_fk` FOREIGN KEY (`parent_comment_id`) REFERENCES `comment` (`comment_id`) ON DELETE CASCADE,
CONSTRAINT `comment_review_review_id_fk` FOREIGN KEY (`review_id`) REFERENCES `review` (`review_id`),
CONSTRAINT `comment_user_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
Expand Down Expand Up @@ -286,4 +286,4 @@ CREATE TABLE `user` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2024-05-21 8:07:34
-- Dump completed on 2024-06-08 13:51:06
8 changes: 4 additions & 4 deletions resources/database/cafe_test_schema.sql
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-- MySQL dump 10.19 Distrib 10.3.38-MariaDB, for debian-linux-gnu (x86_64)
-- MySQL dump 10.19 Distrib 10.3.39-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database: cafe_test
-- ------------------------------------------------------
-- Server version 10.3.38-MariaDB-0ubuntu0.20.04.1
-- Server version 10.3.39-MariaDB-0ubuntu0.20.04.2

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
Expand Down Expand Up @@ -79,7 +79,7 @@ CREATE TABLE `comment` (
KEY `comment_comment_comment_id_fk` (`parent_comment_id`),
KEY `comment_user_user_id_fk` (`user_id`),
KEY `comment_review_review_id_fk` (`review_id`),
CONSTRAINT `comment_comment_comment_id_fk` FOREIGN KEY (`parent_comment_id`) REFERENCES `comment` (`comment_id`),
CONSTRAINT `comment_comment_comment_id_fk` FOREIGN KEY (`parent_comment_id`) REFERENCES `comment` (`comment_id`) ON DELETE CASCADE,
CONSTRAINT `comment_review_review_id_fk` FOREIGN KEY (`review_id`) REFERENCES `review` (`review_id`),
CONSTRAINT `comment_user_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
Expand Down Expand Up @@ -286,4 +286,4 @@ CREATE TABLE `user` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2024-05-21 8:07:34
-- Dump completed on 2024-06-08 13:51:06
33 changes: 19 additions & 14 deletions src/models/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public static function getCategories(): array
return [];
}

$callback = fn($obj): string => $obj->category;
$callback = fn ($obj): string => $obj->category;

return array_map($callback, $result);
}
Expand Down Expand Up @@ -276,19 +276,17 @@ public function getAverageRating(): float
-- get IDs of all clients who purchased current product
SELECT DISTINCT o.client_id
FROM `order` o
JOIN order_product op ON o.order_id = op.order_id
WHERE op.product_id = r.product_id
JOIN order_product op
ON o.order_id = op.order_id
AND op.product_id = r.product_id
)
EOL;

$params = ['product_id' => $this->product_id];

$result = $this->query($query, $params);
$result = $this->query($query, ['product_id' => $this->product_id]);

// Extract the average rating from the result array
if (!empty($result)) {
$averageRating = $result[0]->average_rating;
return $averageRating !== null ? round((float)$averageRating, 2) : 0; // Round to two decimal places
return (float)$result[0]->average_rating;
}

return 0; // No reviews, return 0 as the average rating
Expand Down Expand Up @@ -393,11 +391,18 @@ public function getRatingDistribution(): array
{
// Query the database to get the percentage distribution of ratings
$query = <<< EOL
SELECT rating,
COUNT(*) * 100.0 / (SELECT COUNT(*) FROM review WHERE product_id = :product_id) AS percentage
FROM review
WHERE product_id = :product_id
GROUP BY rating
SELECT rating,
COUNT(*) * 10.0 / (
SELECT COUNT(*)
FROM order_product op
JOIN `order` o ON op.order_id = o.order_id
WHERE op.product_id = :product_id
) AS percentage
FROM review r
JOIN `order` o ON r.client_id = o.client_id
JOIN order_product op ON op.order_id = o.order_id
WHERE op.product_id = :product_id
GROUP BY rating;
EOL;

$params = ['product_id' => $this->product_id];
Expand Down Expand Up @@ -433,4 +438,4 @@ public function updateProduct(array $newProductData): bool

return $this->update($newProductData, ['product_id' => $this->product_id], $this->table);
}
}
}
11 changes: 8 additions & 3 deletions tests/helpers/TestHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,17 @@ public static function createStore(bool $saveToDatabase = true): Store
* Create a review and saves it to database.
* @param Product $product A valid product already present in database
* @param Client $client A valid client already present in database
* @param int|null $rating Rating for review
* @param bool $verified Whether to create an order for client for given product.
* @return Review
* @throws Exception
*/
public static function createReview(Product $product, Client $client, bool $verified = false): Review
{
public static function createReview(
Product $product,
Client $client,
int $rating = null,
bool $verified = false
): Review {
if ($verified) {
// place an order for client and product

Expand Down Expand Up @@ -262,7 +267,7 @@ public static function createReview(Product $product, Client $client, bool $veri
product_id: $product->getProductID(),
client_id: $client->getUserID(),
text: self::$faker->sentence(10),
rating: self::$faker->numberBetween(1, 5)
rating: $rating ?? self::$faker->numberBetween(1, 5)
);

$success = $review->save();
Expand Down
184 changes: 149 additions & 35 deletions tests/models/ProductTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,53 +133,141 @@ public function testToArray(): void

public function testSave(): void
{
$this->markTestIncomplete(
'Use data providers here for at least 3 test cases, ...',
// Prepare test data
$newProductData = [
'name' => 'New Product',
'calories' => 100,
'img_url' => 'new_product.jpeg',
'img_alt_text' => 'New Product Image',
'category' => 'New Category',
'price' => 10.00,
'description' => 'New Product Description'
];

// Create a new product object with the test data
$newProduct = new Product(
$newProductData['name'],
$newProductData['calories'],
$newProductData['img_url'],
$newProductData['img_alt_text'],
$newProductData['category'],
$newProductData['price'],
$newProductData['description']
);

// Save the product to the database
$result = $newProduct->save();

// Assert that the product was saved successfully
$this->assertTrue($result);

// Fetch the saved product from the database
$savedProduct = Product::getByID($newProduct->getProductID());

// Assert that the saved product matches the test data
$this->assertEquals($newProductData['name'], $savedProduct->getName());
$this->assertEquals($newProductData['calories'], $savedProduct->getCalories());
$this->assertEquals($newProductData['img_url'], $savedProduct->getImgRelativePath());
$this->assertEquals($newProductData['img_alt_text'], $savedProduct->getImgAltText());
$this->assertEquals($newProductData['category'], $savedProduct->getCategory());
$this->assertEquals($newProductData['price'], $savedProduct->getPrice());
$this->assertEquals($newProductData['description'], $savedProduct->getDescription());
}


public function testValidate(): void
{
// Validate the dummy product
$errors = $this->dummy_product->validate();

// Check if there are no validation errors
$this->assertEmpty($errors);
// Prepare test data with invalid values
$invalidProductData = [
'name' => '', // Empty name
'calories' => -10, // Negative calories
'img_url' => 'invalid_image.txt', // Invalid image extension
'img_alt_text' => 'In', // Invalid image alt text length
'category' => '', // Empty category
'price' => 0, // Zero price
'description' => '' // Empty description
];

$this->markTestIncomplete(
'This test lacks test cases, ...',
// Create a new product object with the invalid test data
$invalidProduct = new Product(
$invalidProductData['name'],
$invalidProductData['calories'],
$invalidProductData['img_url'],
$invalidProductData['img_alt_text'],
$invalidProductData['category'],
$invalidProductData['price'],
$invalidProductData['description']
);

// Validate the product
$errors = $invalidProduct->validate();

// Assert that validation errors are present for each invalid field
$this->assertArrayHasKey('name', $errors);
$this->assertArrayHasKey('calories', $errors);
$this->assertArrayHasKey('img_url', $errors);
$this->assertArrayHasKey('img_alt_text', $errors);
$this->assertArrayHasKey('category', $errors);
$this->assertArrayHasKey('price', $errors);
$this->assertArrayHasKey('description', $errors);

// Assert that there are exactly 7 validation errors
$this->assertCount(7, $errors);
}


/**
* @throws Exception
*/
public function testGetRatingDistribution(): void
{
$distribution = $this->dummy_product->getRatingDistribution();
// reset data from setUp
self::resetDatabase();

// Check if the distribution contains the expected keys and values
// Here dummy product contains a single review:
$this->assertArrayHasKey($this->dummy_review->getRating(), $distribution);
$this->assertEquals(100.0, $distribution[$this->dummy_review->getRating()]);
// Create a new product for testing
$product = self::createProduct();
$this->dummy_client = self::createClient();

$this->markTestIncomplete(
'This test lacks test cases. This test might fail when getRatingDistribution excludes unverified reviews.',
);
// Create mock review data with different ratings
$verifiedReviewRatings = [5, 4, 3, 2, 1, 5, 4, 3, 4, 5];
// Insert mock review data into the database
foreach ($verifiedReviewRatings as $reviewData) {
self::createReview($product, $this->dummy_client, $reviewData, true);
}

// Create a random number of unverified reviews with different ratings
for ($i = 0; $i < self::$faker->numberBetween(0, 10); $i++) {
$rating = self::$faker->numberBetween(1, 5);
self::createReview($product, self::createClient(), $rating);
}

// Retrieve the rating distribution for the product
$ratingDistribution = $product->getRatingDistribution();

// Assert that the rating distribution is accurate
$expectedDistribution = [
1 => 10.0, // 1 star
2 => 10.0, // 2 stars
3 => 20.0, // 3 stars
4 => 30.0, // 4 stars
5 => 30.0, // 5 stars
];
$this->assertEquals($expectedDistribution, $ratingDistribution);
}

public function testDeleteProduct(): void
{
$product_id = $this->dummy_product->getProductID();
$result = $this->dummy_product->deleteProduct();

// Check if the product was deleted successfully
$this->assertTrue($result);

// Check if the product no longer exists in the database
$product = Product::getByID($product_id);
$this->assertNull($product);

$this->markTestIncomplete(
'This test lacks test cases, ...',
);
// Save the product to the database
$product = $this->dummy_product;

// Delete the product from the database
$success = $product->deleteProduct();
// Assert that the delete operation was successful
self::assertTrue($success);
// Try to retrieve the product by ID to check if it was deleted
$deletedProduct = Product::getByID($product->getProductID());
// Assert that the product is no longer in the database
self::assertNull($deletedProduct);
}

public function testUpdateProduct(): void
Expand Down Expand Up @@ -210,15 +298,41 @@ public function testUpdateProduct(): void
$this->assertEquals('Updated description', $updatedProduct->getDescription());
}

/**
* @throws Exception
*/
public function testGetAverageRating(): void
{
$averageRating = $this->dummy_product->getAverageRating();
// reset database as we don't want previously created reviews from setUp.
self::resetDatabase();

$this->assertNotEquals(999.0, $averageRating);
$this->dummy_product = self::createProduct();
$this->dummy_client = self::createClient();

$this->markTestIncomplete(
'This test lacks test cases, ...',
);
// Create a random number of verified reviews with different ratings
$verifiedReviewRatings = [];
for ($i = 0; $i < self::$faker->numberBetween(0, 10); $i++) {
$rating = self::$faker->numberBetween(1, 5);
$verifiedReviewRatings[] = $rating;
self::createReview($this->dummy_product, $this->dummy_client, $rating, true);
}

// Note: $this->dummy_client can be a verified reviewer do not write unverified reviews with it

// Create a random number of unverified reviews with different ratings
for ($i = 0; $i < self::$faker->numberBetween(0, 10); $i++) {
$rating = self::$faker->numberBetween(1, 5);
self::createReview($this->dummy_product, self::createClient(), $rating);
}

// Retrieve the average rating for the product
$averageRating = $this->dummy_product->getAverageRating();

// Assert that the average rating is accurate
$expectedAverageRating = count($verifiedReviewRatings) === 0 ? 0 : (float)array_sum(
$verifiedReviewRatings
) / count($verifiedReviewRatings);
$this->assertEqualsWithDelta($expectedAverageRating, $averageRating, 0.0001);
}

public function testGetReviews(): void
Expand Down
Loading

0 comments on commit 4a263d4

Please sign in to comment.