From 01b414c22ce646b4adc7747e9bb5ec4b1ccca1b8 Mon Sep 17 00:00:00 2001 From: "Christopher C. Wells" Date: Sun, 28 Mar 2021 09:18:30 -0700 Subject: [PATCH] Add tests for Support classes --- app/Support/Nutrients.php | 14 +--- database/factories/FoodFactory.php | 76 +++++++++++++++-- phpunit.xml | 4 +- tests/Feature/ExampleTest.php | 21 ----- tests/Feature/RegistrationTest.php | 32 -------- tests/Feature/Support/NutrientsTest.php | 104 ++++++++++++++++++++++++ tests/Unit/ExampleTest.php | 18 ---- tests/Unit/Support/ArrayFormatTest.php | 40 +++++++++ tests/Unit/Support/NumberTest.php | 70 ++++++++++++++++ 9 files changed, 285 insertions(+), 94 deletions(-) delete mode 100644 tests/Feature/ExampleTest.php delete mode 100644 tests/Feature/RegistrationTest.php create mode 100644 tests/Feature/Support/NutrientsTest.php delete mode 100644 tests/Unit/ExampleTest.php create mode 100644 tests/Unit/Support/ArrayFormatTest.php create mode 100644 tests/Unit/Support/NumberTest.php diff --git a/app/Support/Nutrients.php b/app/Support/Nutrients.php index 346e39d..4ea4e89 100644 --- a/app/Support/Nutrients.php +++ b/app/Support/Nutrients.php @@ -71,12 +71,6 @@ class Nutrients /** * Calculate a nutrient multiplier for a Food. - * - * @param \App\Models\Food $food - * @param float $amount - * @param string|null $fromUnit - * - * @return float */ public static function calculateFoodNutrientMultiplier( Food $food, @@ -93,6 +87,7 @@ class Nutrients return $amount / $food->serving_weight; } + // @todo Determine if `empty($food->serving_unit)` case makes sense. if ( empty($fromUnit) || empty($food->serving_unit) @@ -130,13 +125,6 @@ class Nutrients /** * Calculate a nutrient amount for a recipe. - * - * @param \App\Models\Recipe $recipe - * @param string $nutrient - * @param float $amount - * @param string $fromUnit - * - * @return float */ public static function calculateRecipeNutrientAmount( Recipe $recipe, diff --git a/database/factories/FoodFactory.php b/database/factories/FoodFactory.php index 4cbd4cf..5e45f68 100644 --- a/database/factories/FoodFactory.php +++ b/database/factories/FoodFactory.php @@ -8,21 +8,81 @@ use Illuminate\Database\Eloquent\Factories\Factory; class FoodFactory extends Factory { /** - * The name of the factory's corresponding model. - * - * @var string + * {@inheritdoc} */ protected $model = Food::class; /** - * Define the model's default state. - * - * @return array + * {@inheritdoc} */ - public function definition() + public function definition(): array { return [ - // + 'name' => $this->faker->word, + 'detail' => $this->faker->sentence(2), + 'brand' => $this->faker->word, + 'source' => $this->faker->url, + 'serving_size' => $this->faker->randomFloat(2, 1/2, 5), + 'serving_unit' => $this->faker->randomElement(['tsp', 'tbsp', 'cup']), + 'serving_weight' => $this->faker->numberBetween(5, 500), + 'calories' => $this->faker->randomFloat(2, 0, 100), + 'fat' => $this->faker->randomFloat(2, 0, 10), + 'cholesterol' => $this->faker->randomFloat(2, 0, 100), + 'sodium' => $this->faker->randomFloat(2, 0, 500), + 'carbohydrates' => $this->faker->randomFloat(2, 0, 20), + 'protein' => $this->faker->randomFloat(2, 0, 20), ]; } + + /** + * Make instance with "tsp" serving unit. + */ + public function tspServingUnit() + { + return $this->state(function (array $attributes) { + return [ + 'serving_unit' => 'tsp', + 'serving_size' => 1, + ]; + }); + } + + /** + * Make instance with "tbsp" serving unit. + */ + public function tbspServingUnit() + { + return $this->state(function (array $attributes) { + return [ + 'serving_unit' => 'tbsp', + 'serving_size' => 1, + ]; + }); + } + + /** + * Make instance with "cup" serving unit. + */ + public function cupServingUnit() + { + return $this->state(function (array $attributes) { + return [ + 'serving_unit' => 'cup', + 'serving_size' => 1, + ]; + }); + } + + /** + * Make instance with no" serving unit. + */ + public function noServingUnit() + { + return $this->state(function (array $attributes) { + return [ + 'serving_unit' => null, + 'serving_unit_name' => 'head' + ]; + }); + } } diff --git a/phpunit.xml b/phpunit.xml index 4ae4d97..76a606b 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -21,8 +21,8 @@ - - + + diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php deleted file mode 100644 index cdb5111..0000000 --- a/tests/Feature/ExampleTest.php +++ /dev/null @@ -1,21 +0,0 @@ -get('/'); - - $response->assertStatus(200); - } -} diff --git a/tests/Feature/RegistrationTest.php b/tests/Feature/RegistrationTest.php deleted file mode 100644 index 6dd5ff8..0000000 --- a/tests/Feature/RegistrationTest.php +++ /dev/null @@ -1,32 +0,0 @@ -get('/register'); - - $response->assertStatus(200); - } - - public function test_new_users_can_register() - { - $response = $this->post('/register', [ - 'name' => 'Test User', - 'email' => 'test@example.com', - 'password' => 'password', - 'password_confirmation' => 'password', - ]); - - $this->assertAuthenticated(); - $response->assertRedirect(RouteServiceProvider::HOME); - } -} diff --git a/tests/Feature/Support/NutrientsTest.php b/tests/Feature/Support/NutrientsTest.php new file mode 100644 index 0000000..81cc776 --- /dev/null +++ b/tests/Feature/Support/NutrientsTest.php @@ -0,0 +1,104 @@ +expectException(\DomainException::class); + Nutrients::calculateFoodNutrientMultiplier($food, $amount, $fromUnit); + } + + /** + * Test valid Food nutrient multiplier calculation. + * + * @dataProvider foodsValidNutrientMultipliersProvider + */ + public function testCalculateFoodValidNutrientMultiplier( + Food $food, + float $amount, + string $fromUnit, + float $expectedMultiplier + ): void { + $this->assertEquals( + Nutrients::calculateFoodNutrientMultiplier($food, $amount, $fromUnit), + $expectedMultiplier + ); + } + + /** + * Data providers. + */ + + /** + * Provide example foods and expected nutrient multipliers. + */ + public function foodsInvalidNutrientMultipliersProvider(): array { + $this->refreshApplication(); + + /** @var \App\Models\Food $foodInvalidUnit */ + $foodInvalidUnit = Food::factory()->make(['serving_unit' => 'invalid']); + + return [ + [$foodInvalidUnit, 1, 'tsp'], + [$foodInvalidUnit, 1, 'tbsp'], + [$foodInvalidUnit, 1, 'cup'], + [Food::factory()->tspServingUnit()->make(), 1, 'invalid'], + ]; + } + + /** + * Provide example foods and expected nutrient multipliers. + */ + public function foodsValidNutrientMultipliersProvider(): array { + $this->refreshApplication(); + + /** @var \App\Models\Food[] $foods */ + $foods = [ + 'tsp' => Food::factory()->tspServingUnit()->make(), + 'tbsp' => Food::factory()->tbspServingUnit()->make(), + 'cup' => Food::factory()->cupServingUnit()->make(), + 'none' => Food::factory()->noServingUnit()->make(), + ]; + + return [ + [$foods['tsp'], $foods['tsp']->serving_weight, 'oz', Nutrients::$gramsPerOunce], + [$foods['tsp'], 1, 'serving', 1], + [$foods['tsp'], $foods['tsp']->serving_weight * 1.5, 'gram', 1.5], + [$foods['tsp'], 2, 'tsp', 2], + [$foods['tsp'], 1, 'tbsp', 3], + [$foods['tsp'], 1, 'cup', 48], + [$foods['tbsp'], $foods['tbsp']->serving_weight, 'oz', Nutrients::$gramsPerOunce], + [$foods['tbsp'], 1, 'serving', 1], + [$foods['tbsp'], $foods['tbsp']->serving_weight * 2, 'gram', 2], + [$foods['tbsp'], 2, 'tsp', 2/3], + [$foods['tbsp'], 1, 'tbsp', 1], + [$foods['tbsp'], 2, 'cup', 32], + [$foods['cup'], $foods['cup']->serving_weight, 'oz', Nutrients::$gramsPerOunce], + [$foods['cup'], 1, 'serving', 1], + [$foods['cup'], $foods['cup']->serving_weight * 2.25, 'gram', 2.25], + [$foods['cup'], 3, 'tsp', 1/16], + [$foods['cup'], 2, 'tbsp', 1/8], + [$foods['cup'], 5, 'cup', 5], + [$foods['none'], $foods['none']->serving_weight, 'oz', Nutrients::$gramsPerOunce], + [$foods['none'], 1, 'serving', 1], + [$foods['none'], $foods['none']->serving_weight * 3.0125, 'gram', 3.0125], + ]; + } +} diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php deleted file mode 100644 index 358cfc8..0000000 --- a/tests/Unit/ExampleTest.php +++ /dev/null @@ -1,18 +0,0 @@ -assertTrue(true); - } -} diff --git a/tests/Unit/Support/ArrayFormatTest.php b/tests/Unit/Support/ArrayFormatTest.php new file mode 100644 index 0000000..8753126 --- /dev/null +++ b/tests/Unit/Support/ArrayFormatTest.php @@ -0,0 +1,40 @@ + [ + 0 => 'ingredient-0', + 1 => 'ingredient-1', + 2 => 'ingredient-2', + 3 => 'ingredient-3', + ], + 'amount' => [ + 0 => 'amount-0', + 1 => 'amount-1', + 2 => 'amount-2', + 3 => 'amount-3', + ], + ]; + $expected = [ + ['ingredient' => 'ingredient-0', 'amount' => 'amount-0'], + ['ingredient' => 'ingredient-1', 'amount' => 'amount-1'], + ['ingredient' => 'ingredient-2', 'amount' => 'amount-2'], + ['ingredient' => 'ingredient-3', 'amount' => 'amount-3'], + ]; + $this->assertEqualsCanonicalizing($expected, ArrayFormat::flipTwoDimensionalKeys($input)); + } +} diff --git a/tests/Unit/Support/NumberTest.php b/tests/Unit/Support/NumberTest.php new file mode 100644 index 0000000..df39737 --- /dev/null +++ b/tests/Unit/Support/NumberTest.php @@ -0,0 +1,70 @@ +assertIsFloat($result); + $this->assertEquals($expectedFloat, $result); + } + + /** + * Test (fraction) string to float conversion. + * + * @dataProvider fractionStringFloatsProvider + * + * @see \App\Support\Number::fractionStringFromFloat() + */ + public function testFractionStringFromFloat(string $expectedString, float $float): void + { + $result = Number::fractionStringFromFloat($float); + $this->assertIsString($result); + $this->assertEquals($expectedString, $result); + } + + /** + * Data providers. + */ + + /** + * Provide decimal string and float data. + * + * @see \Tests\Unit\Support\NumberTest::testFloatFromString() + */ + public function decimalStringFloatsProvider(): array { + return [ + ['0.0', 0.0], ['0.125', 1/8], ['0.25', 1/4], ['0.5', 1/2], + ['0.75', 3/4], ['1.0', 1.0], ['1.25', 1.25], ['1.5', 1.5], + ['2.5', 2.5], ['2.75', 2.75], + ]; + } + + /** + * Provide fraction string and float data. + * + * @see \Tests\Unit\Support\NumberTest::testFloatFromString() + * @see \Tests\Unit\Support\NumberTest::testFractionStringFromFloat() + */ + public function fractionStringFloatsProvider(): array { + return [ + ['0', 0.0], ['1/8', 1/8], ['1/4', 1/4], ['1/3', 1/3], ['1/2', 1/2], + ['2/3', 2/3], ['3/4', 3/4], ['1', 1.0], ['1 1/4', 1.25], + ['1 1/2', 1.5], ['2 1/2', 2.5], ['2 3/4', 2.75], + ]; + } +}