Initial checkin
This commit is contained in:
commit
6e662f0263
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/vendor
|
||||||
|
/composer.lock
|
10
README.md
Normal file
10
README.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# NoccyLabs Juicer
|
||||||
|
|
||||||
|
This is a library to help write juice-mixing stuff in PHP.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Mix by weight or by volume.
|
||||||
|
* Calculate weights for mixing based on the VG/PG ratio or a specific values.
|
||||||
|
* Calculate weights for nicotine based on the nicotine strength and base.
|
||||||
|
* Interfaces allow for custom entity-backed implementations.
|
17
composer.json
Normal file
17
composer.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "noccylabs/juicer",
|
||||||
|
"description": "E-liquid mixing library",
|
||||||
|
"type": "library",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Christopher Vagnetoft",
|
||||||
|
"email": "cvagnetoft@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"NoccyLabs\\Juicer\\": "src/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
phpunit.xml
Normal file
21
phpunit.xml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/7.5/phpunit.xsd"
|
||||||
|
bootstrap="vendor/autoload.php"
|
||||||
|
forceCoversAnnotation="true"
|
||||||
|
beStrictAboutCoversAnnotation="true"
|
||||||
|
beStrictAboutOutputDuringTests="true"
|
||||||
|
beStrictAboutTodoAnnotatedTests="true"
|
||||||
|
verbose="true">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="default">
|
||||||
|
<directory suffix="Test.php">tests</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||||
|
<directory suffix=".php">src</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
73
src/Ingredient/Base.php
Normal file
73
src/Ingredient/Base.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Ingredient;
|
||||||
|
|
||||||
|
class Base
|
||||||
|
{
|
||||||
|
const MASS_PG = 1.038;
|
||||||
|
const MASS_VG = 1.26;
|
||||||
|
|
||||||
|
protected static $MASS = [
|
||||||
|
'PG' => self::MASS_PG,
|
||||||
|
'VG' => self::MASS_VG,
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $base;
|
||||||
|
|
||||||
|
protected $components = [];
|
||||||
|
|
||||||
|
protected $specificGravity;
|
||||||
|
|
||||||
|
public function __construct(string $base)
|
||||||
|
{
|
||||||
|
$this->components = self::parseComponents($base);
|
||||||
|
$this->base = $base;
|
||||||
|
$this->specificGravity = self::calculateSpecificGravity($this->components);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSpecificGravity(): float
|
||||||
|
{
|
||||||
|
return $this->specificGravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getComponents(): array
|
||||||
|
{
|
||||||
|
return $this->components;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function parseComponents(string $base)
|
||||||
|
{
|
||||||
|
$found = [];
|
||||||
|
if (!preg_match('/^([A-Z]+)([0-9]{1,3}+)$/i', $base, $match)) {
|
||||||
|
throw new \Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($match[1] == "PG") {
|
||||||
|
return [
|
||||||
|
'PG' => $match[2],
|
||||||
|
'VG' => 100 - $match[2]
|
||||||
|
];
|
||||||
|
} elseif ($match[1] == "VG") {
|
||||||
|
return [
|
||||||
|
'PG' => 100 - $match[2],
|
||||||
|
'VG' => $match[2]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function calculateSpecificGravity(array $components): float
|
||||||
|
{
|
||||||
|
$specificGravity = 0.0;
|
||||||
|
foreach ($components as $component=>$percent) {
|
||||||
|
$percentFloat = $percent / 100;
|
||||||
|
$specificGravity += (self::$MASS[$component] * $percentFloat);
|
||||||
|
}
|
||||||
|
return $specificGravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
55
src/Ingredient/Ingredient.php
Normal file
55
src/Ingredient/Ingredient.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Ingredient;
|
||||||
|
|
||||||
|
class Ingredient implements IngredientInterface
|
||||||
|
{
|
||||||
|
protected $name;
|
||||||
|
|
||||||
|
protected $brand;
|
||||||
|
|
||||||
|
protected $percent;
|
||||||
|
|
||||||
|
protected $base;
|
||||||
|
|
||||||
|
public function __construct(string $name, ?string $brand=null, float $percent=0.0, string $base="PG100")
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->brand = $brand;
|
||||||
|
$this->percent = $percent;
|
||||||
|
$this->base = $base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getFlavorName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getFlavorBrand(): ?string
|
||||||
|
{
|
||||||
|
return $this->brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getPercent(): float
|
||||||
|
{
|
||||||
|
return $this->percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getBase(): ?string
|
||||||
|
{
|
||||||
|
return $this->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/Ingredient/IngredientInterface.php
Normal file
37
src/Ingredient/IngredientInterface.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Ingredient;
|
||||||
|
|
||||||
|
interface IngredientInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the flavor
|
||||||
|
*
|
||||||
|
* @return string The name of the flavor
|
||||||
|
*/
|
||||||
|
public function getFlavorName(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the short name of the flavor brand. This should be the upper-case
|
||||||
|
* abbreviation, and not the complete name.
|
||||||
|
*
|
||||||
|
* @return string|null The upper-case abbreviation of the flavor brand
|
||||||
|
*/
|
||||||
|
public function getFlavorBrand(): ?string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the percent (0-100)
|
||||||
|
*
|
||||||
|
* @return float The percent of the flavor to use
|
||||||
|
*/
|
||||||
|
public function getPercent(): float;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the base mix used for this flavoring (usually PG100)
|
||||||
|
*
|
||||||
|
* @return string|null The base mix used
|
||||||
|
*/
|
||||||
|
public function getBase(): ?string;
|
||||||
|
|
||||||
|
}
|
24
src/Ingredient/NicotineBase.php
Normal file
24
src/Ingredient/NicotineBase.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Ingredient;
|
||||||
|
|
||||||
|
class NicotineBase
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $base;
|
||||||
|
|
||||||
|
protected $strength;
|
||||||
|
|
||||||
|
public function __construct(Base $base, int $strength)
|
||||||
|
{
|
||||||
|
$this->base = $base;
|
||||||
|
$this->nicotineStrength = $strength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSpecificGravity(): float
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
49
src/Recipe/Exporter/JsonExporter.php
Normal file
49
src/Recipe/Exporter/JsonExporter.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe\Exporter;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Recipe\RecipeInterface;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
|
||||||
|
|
||||||
|
class JsonExporter
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public function export(RecipeInterface $recipe)
|
||||||
|
{
|
||||||
|
$ingredients = [];
|
||||||
|
/** @var IngredientInterface $ingredient */
|
||||||
|
foreach ($recipe->getIngredients() as $ingredient) {
|
||||||
|
$ingredients[] = [
|
||||||
|
'brand' => $ingredient->getFlavorBrand(),
|
||||||
|
'flavor' => $ingredient->getFlavorName(),
|
||||||
|
'percent' => $ingredient->getPercent()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$document = [
|
||||||
|
'recipe' => $recipe->getRecipeName(),
|
||||||
|
'author' => $recipe->getRecipeAuthor(),
|
||||||
|
'tags' => $recipe->getTags(),
|
||||||
|
'description' => $recipe->getDescription(),
|
||||||
|
'extra' => $recipe->getExtra(),
|
||||||
|
'ingredients' => $ingredients
|
||||||
|
];
|
||||||
|
|
||||||
|
return json_encode($document,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function writeToFile(RecipeInterface $recipe, string $filename)
|
||||||
|
{
|
||||||
|
$json = $this->export($recipe);
|
||||||
|
|
||||||
|
$fd = fopen($filename, "w");
|
||||||
|
if (!$fd) {
|
||||||
|
throw new \InvalidArgumentException();
|
||||||
|
}
|
||||||
|
fwrite($fd, $json, strlen($json));
|
||||||
|
fclose($fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
44
src/Recipe/Importer/JsonImporter.php
Normal file
44
src/Recipe/Importer/JsonImporter.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe\Importer;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Recipe\RecipeInterface;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
|
||||||
|
use NoccyLabs\Juicer\Recipe\Recipe;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Ingredient;
|
||||||
|
|
||||||
|
class JsonImporter
|
||||||
|
{
|
||||||
|
|
||||||
|
public function import(string $json): RecipeInterface
|
||||||
|
{
|
||||||
|
$data = json_decode($json);
|
||||||
|
|
||||||
|
|
||||||
|
$recipe = new Recipe();
|
||||||
|
$recipe->setRecipeName(@$data->recipe);
|
||||||
|
$recipe->setRecipeAuthor(@$data->author);
|
||||||
|
$recipe->setDescription(@$data->description);
|
||||||
|
$recipe->setExtra((array)@$data->extra);
|
||||||
|
|
||||||
|
foreach ((array)@$data->ingredients as $ingredientData) {
|
||||||
|
$ingredient = new Ingredient($ingredientData->flavor, $ingredientData->brand, $ingredientData->percent);
|
||||||
|
$recipe->addIngredient($ingredient);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readFromFile(string $filename): RecipeInterface
|
||||||
|
{
|
||||||
|
$fd = fopen($filename, "r");
|
||||||
|
if (!$fd) {
|
||||||
|
throw new \InvalidArgumentException();
|
||||||
|
}
|
||||||
|
$json = fread($fd, filesize($filename));
|
||||||
|
fclose($fd);
|
||||||
|
|
||||||
|
return $this->import($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
70
src/Recipe/Mixer/MeasuredIngredient.php
Normal file
70
src/Recipe/Mixer/MeasuredIngredient.php
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe\Mixer;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Base;
|
||||||
|
|
||||||
|
class MeasuredIngredient implements IngredientInterface
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
protected $name;
|
||||||
|
/** @var string|null */
|
||||||
|
protected $brand;
|
||||||
|
/** @var string */
|
||||||
|
protected $base;
|
||||||
|
/** @var float The apparent specific gravity (ASG) of this ingredient in g/mL */
|
||||||
|
protected $asg;
|
||||||
|
/** @var float The percent of this ingredient in the final mix */
|
||||||
|
protected $pecent;
|
||||||
|
/** @var float Volume in milliliters (mL) */
|
||||||
|
protected $volume;
|
||||||
|
/** @var float Weight in grams (g) */
|
||||||
|
protected $weight;
|
||||||
|
|
||||||
|
public function __construct(string $name, ?string $brand, string $base, float $asg, float $percent, float $volume)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->brand = $brand;
|
||||||
|
$this->base = $base;
|
||||||
|
$this->asg = $asg;
|
||||||
|
$this->percent = $percent;
|
||||||
|
$this->volume = $volume;
|
||||||
|
$this->weight = $volume * $asg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFlavorName(): string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFlavorBrand(): ?string
|
||||||
|
{
|
||||||
|
return $this->brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBase(): ?string
|
||||||
|
{
|
||||||
|
return $this->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPercent(): float
|
||||||
|
{
|
||||||
|
return $this->percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSpecificGravity(): float
|
||||||
|
{
|
||||||
|
return $this->asg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVolume(): float
|
||||||
|
{
|
||||||
|
return $this->volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWeight(): float
|
||||||
|
{
|
||||||
|
return $this->weight;
|
||||||
|
}
|
||||||
|
}
|
31
src/Recipe/Mixer/Mixer.php
Normal file
31
src/Recipe/Mixer/Mixer.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe\Mixer;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
|
||||||
|
use NoccyLabs\Juicer\Recipe\RecipeInterface;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Base;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\NicotineBase;
|
||||||
|
|
||||||
|
class Mixer
|
||||||
|
{
|
||||||
|
|
||||||
|
public function mixRecipe(RecipeInterface $recipe, int $volume, Base $base, int $nicotineStrength, ?NicotineBase $nicotineBase=null)
|
||||||
|
{
|
||||||
|
$mixed = [];
|
||||||
|
|
||||||
|
|
||||||
|
$components = $base->getComponents();
|
||||||
|
|
||||||
|
if (array_key_exists('VG', $components) && $components['VG'] > 0) {
|
||||||
|
$mixed[] = new MeasuredIngredient("VG", null, "VG100", Base::MASS_VG, 100, $volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('PG', $components) && $components['PG'] > 0) {
|
||||||
|
$mixed[] = new MeasuredIngredient("PG", null, "PG100", Base::MASS_PG, 100, $volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $mixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
110
src/Recipe/Recipe.php
Normal file
110
src/Recipe/Recipe.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
|
||||||
|
|
||||||
|
class Recipe implements RecipeInterface
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
protected $name;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $author;
|
||||||
|
|
||||||
|
/** @var string[] */
|
||||||
|
protected $tags = [];
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $extra = [];
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $description;
|
||||||
|
|
||||||
|
/** @var IngredientInterface[] */
|
||||||
|
protected $ingredients = [];
|
||||||
|
|
||||||
|
public function setRecipeName(?string $name)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRecipeAuthor(?string $author)
|
||||||
|
{
|
||||||
|
$this->author = $author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTags(array $tags)
|
||||||
|
{
|
||||||
|
$this->tags = $tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addTag(string $tag)
|
||||||
|
{
|
||||||
|
$this->tags[] = $tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDescription(?string $description)
|
||||||
|
{
|
||||||
|
$this->description = $description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addIngredient(IngredientInterface $ingredient)
|
||||||
|
{
|
||||||
|
$this->ingredients[] = $ingredient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setExtra(array $extra)
|
||||||
|
{
|
||||||
|
$this->extra = $extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getRecipeName(): ?string
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getRecipeAuthor(): ?string
|
||||||
|
{
|
||||||
|
return $this->author;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getTags(): array
|
||||||
|
{
|
||||||
|
return $this->tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getExtra(): array
|
||||||
|
{
|
||||||
|
return $this->extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getDescription(): ?string
|
||||||
|
{
|
||||||
|
return $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function getIngredients(): array
|
||||||
|
{
|
||||||
|
return $this->ingredients;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
src/Recipe/RecipeInterface.php
Normal file
27
src/Recipe/RecipeInterface.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Ingredient\IngredientInterface;
|
||||||
|
|
||||||
|
interface RecipeInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getRecipeName(): ?string;
|
||||||
|
|
||||||
|
public function getRecipeAuthor(): ?string;
|
||||||
|
|
||||||
|
public function getTags(): array;
|
||||||
|
|
||||||
|
public function getDescription(): ?string;
|
||||||
|
|
||||||
|
public function getExtra(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array containing the ingredients of the recipe.
|
||||||
|
*
|
||||||
|
* @return IngredientInterface[] The ingredients
|
||||||
|
*/
|
||||||
|
public function getIngredients(): array;
|
||||||
|
|
||||||
|
}
|
28
tests/Ingredient/BaseTest.php
Normal file
28
tests/Ingredient/BaseTest.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Ingredient;
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTest extends \PhpUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
public function getBaseAsgData()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[ 'PG100', Base::MASS_PG ],
|
||||||
|
[ 'VG100', Base::MASS_VG ],
|
||||||
|
// NOTE: The internet claims we should get (for 50/50;) 1.1425g/mL
|
||||||
|
// but calculating a 50/50 by volume base gives 1.149g/mL.
|
||||||
|
[ 'VG50', 1.149 ]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider getBaseAsgData
|
||||||
|
*/
|
||||||
|
public function testThatTheBaseHasTheProperApparentSpecificGravity($base, $expected)
|
||||||
|
{
|
||||||
|
$base = new Base($base);
|
||||||
|
$this->assertEquals($expected, $base->getSpecificGravity());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
65
tests/Recipe/Exporter/JsonExporterTest.php
Normal file
65
tests/Recipe/Exporter/JsonExporterTest.php
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe\Exporter;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Recipe\Recipe;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Ingredient;
|
||||||
|
|
||||||
|
class JsonExporterTest extends \PhpUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
public function testThatRecipesCanBeExportedToJson()
|
||||||
|
{
|
||||||
|
$recipe = new Recipe();
|
||||||
|
$recipe->setRecipeName("foo");
|
||||||
|
$recipe->setRecipeAuthor("bar");
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Recipe::class, $recipe);
|
||||||
|
$this->assertEquals("foo", $recipe->getRecipeName());
|
||||||
|
$this->assertEquals("bar", $recipe->getRecipeAuthor());
|
||||||
|
|
||||||
|
$exporter = new JsonExporter();
|
||||||
|
|
||||||
|
$exported = $exporter->export($recipe);
|
||||||
|
$expected = json_encode([
|
||||||
|
'recipe' => 'foo',
|
||||||
|
'author' => 'bar',
|
||||||
|
'tags' => [],
|
||||||
|
'description' => null,
|
||||||
|
'extra' => [],
|
||||||
|
'ingredients' => []
|
||||||
|
], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $exported);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testThatRecipesWithIngredientsCanBeExportedToJson()
|
||||||
|
{
|
||||||
|
$recipe = new Recipe();
|
||||||
|
$recipe->setRecipeName("foo");
|
||||||
|
$recipe->setRecipeAuthor("bar");
|
||||||
|
$recipe->addIngredient(new Ingredient("Cherry", "FA", 1));
|
||||||
|
$recipe->addIngredient(new Ingredient("Vanilla Swirl", "TFA", 2));
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Recipe::class, $recipe);
|
||||||
|
$this->assertEquals("foo", $recipe->getRecipeName());
|
||||||
|
$this->assertEquals("bar", $recipe->getRecipeAuthor());
|
||||||
|
|
||||||
|
$exporter = new JsonExporter();
|
||||||
|
|
||||||
|
$exported = $exporter->export($recipe);
|
||||||
|
$expected = json_encode([
|
||||||
|
'recipe' => 'foo',
|
||||||
|
'author' => 'bar',
|
||||||
|
'tags' => [],
|
||||||
|
'description' => null,
|
||||||
|
'extra' => [],
|
||||||
|
'ingredients' => [
|
||||||
|
[ 'brand' => 'FA', 'flavor' => 'Cherry', 'percent' => 1 ],
|
||||||
|
[ 'brand' => 'TFA', 'flavor' => 'Vanilla Swirl', 'percent' => 2 ]
|
||||||
|
]
|
||||||
|
], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $exported);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
tests/Recipe/Importer/JsonImporterTest.php
Normal file
45
tests/Recipe/Importer/JsonImporterTest.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe\Importer;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Recipe\Recipe;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Ingredient;
|
||||||
|
use NoccyLabs\Juicer\Recipe\Exporter\JsonExporter;
|
||||||
|
|
||||||
|
class JsonImporterTest extends \PhpUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
public function testThatRecipesCanBeImportedFromJson()
|
||||||
|
{
|
||||||
|
|
||||||
|
$json = '{ "recipe":"foo", "author":"bar", "ingredients": [{"flavor":"Cherry", "brand":"FA", "percent":1}] }';
|
||||||
|
|
||||||
|
$importer = new JsonImporter();
|
||||||
|
$recipe = $importer->import($json);
|
||||||
|
|
||||||
|
$this->assertEquals("foo", $recipe->getRecipeName());
|
||||||
|
$this->assertEquals("bar", $recipe->getRecipeAuthor());
|
||||||
|
|
||||||
|
$this->assertCount(1, $recipe->getIngredients());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testThatRecipesCanBeImportedFromExportedJson()
|
||||||
|
{
|
||||||
|
|
||||||
|
$recipe = new Recipe();
|
||||||
|
$recipe->setRecipeName("foo");
|
||||||
|
$recipe->setRecipeAuthor("bar");
|
||||||
|
$recipe->addIngredient(new Ingredient("Cherry", "FA", 1));
|
||||||
|
$recipe->addIngredient(new Ingredient("Vanilla Swirl", "TFA", 2));
|
||||||
|
|
||||||
|
$exporter = new JsonExporter();
|
||||||
|
$exported = $exporter->export($recipe);
|
||||||
|
|
||||||
|
$importer = new JsonImporter();
|
||||||
|
$importedRecipe = $importer->import($exported);
|
||||||
|
|
||||||
|
$this->assertEquals($recipe, $importedRecipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
59
tests/Recipe/Mixer/MixerTest.php
Normal file
59
tests/Recipe/Mixer/MixerTest.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe\Mixer;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Recipe\Recipe;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Ingredient;
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Base;
|
||||||
|
|
||||||
|
class MixerTest extends \PhpUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
public function testMixingEmptyRecipesWithVg()
|
||||||
|
{
|
||||||
|
$recipe = new Recipe();
|
||||||
|
$mixer = new Mixer();
|
||||||
|
|
||||||
|
$base = new Base("VG100");
|
||||||
|
$mixed = $mixer->mixRecipe($recipe, 10, $base, 0);
|
||||||
|
|
||||||
|
$this->assertCount(1, $mixed);
|
||||||
|
$mixedVg = reset($mixed);
|
||||||
|
|
||||||
|
$this->assertEquals(10, $mixedVg->getVolume());
|
||||||
|
$this->assertEquals("VG", $mixedVg->getFlavorName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMixingEmptyRecipesWithPg()
|
||||||
|
{
|
||||||
|
$recipe = new Recipe();
|
||||||
|
$mixer = new Mixer();
|
||||||
|
|
||||||
|
$base = new Base("PG100");
|
||||||
|
$mixed = $mixer->mixRecipe($recipe, 10, $base, 0);
|
||||||
|
|
||||||
|
$this->assertCount(1, $mixed);
|
||||||
|
$mixedPg = reset($mixed);
|
||||||
|
|
||||||
|
$this->assertEquals(10, $mixedPg->getVolume());
|
||||||
|
$this->assertEquals("PG", $mixedPg->getFlavorName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMixingEmptyRecipesWith70Vg30Pg()
|
||||||
|
{
|
||||||
|
$recipe = new Recipe();
|
||||||
|
$mixer = new Mixer();
|
||||||
|
|
||||||
|
$base = new Base("VG70");
|
||||||
|
$mixed = $mixer->mixRecipe($recipe, 10, $base, 0);
|
||||||
|
|
||||||
|
$this->assertCount(2, $mixed);
|
||||||
|
|
||||||
|
$mixedVg = array_shift($mixed);
|
||||||
|
$this->assertEquals(10, $mixedVg->getVolume());
|
||||||
|
$this->assertEquals("VG", $mixedVg->getFlavorName());
|
||||||
|
$mixedPg = array_shift($mixed);
|
||||||
|
$this->assertEquals(10, $mixedPg->getVolume());
|
||||||
|
$this->assertEquals("PG", $mixedPg->getFlavorName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
tests/Recipe/RecipeTest.php
Normal file
28
tests/Recipe/RecipeTest.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace NoccyLabs\Juicer\Recipe;
|
||||||
|
|
||||||
|
use NoccyLabs\Juicer\Ingredient\Ingredient;
|
||||||
|
|
||||||
|
class RecipeTest extends \PhpUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public function testCreatingAndModifyingRecipes()
|
||||||
|
{
|
||||||
|
$recipe = new Recipe();
|
||||||
|
$recipe->setRecipeName("foo");
|
||||||
|
$recipe->setRecipeAuthor("bar");
|
||||||
|
|
||||||
|
$ingredient1 = new Ingredient("Ingredient 1");
|
||||||
|
$ingredient2 = new Ingredient("Ingredient 2");
|
||||||
|
|
||||||
|
$recipe->addIngredient($ingredient1);
|
||||||
|
$recipe->addIngredient($ingredient2);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Recipe::class, $recipe);
|
||||||
|
$this->assertEquals("foo", $recipe->getRecipeName());
|
||||||
|
$this->assertEquals("bar", $recipe->getRecipeAuthor());
|
||||||
|
$this->assertEquals([$ingredient1, $ingredient2], $recipe->getIngredients());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user