<pman>Intégration de la branche rel82-0.7.0
This commit is contained in:
		
						commit
						9ccc9d984f
					
				
							
								
								
									
										10
									
								
								CHANGES.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGES.md
									
									
									
									
									
								
							| @ -1,3 +1,13 @@ | ||||
| ## Release 0.7.0p82 du 22/10/2025-18:36 | ||||
| 
 | ||||
| ## Release 0.7.0p74 du 22/10/2025-18:33 | ||||
| 
 | ||||
| * `5e41e7d` gestion simplifiée des schéma | ||||
| * `efb4f03` importation Hour et Time et d'autres vclasses | ||||
| * `4f0d6d4` function isa() pour les vclasses | ||||
| * `cfb8f0d` corriger la prise en compte des configurations de branche | ||||
| * nombreuses autres modifications non documentées ici | ||||
| 
 | ||||
| ## Release 0.6.1p82 du 03/06/2025-10:22 | ||||
| 
 | ||||
| ## Release 0.6.1p74 du 03/06/2025-10:21 | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| 0.6.1 | ||||
| 0.7.0 | ||||
|  | ||||
| @ -366,7 +366,8 @@ function load_config() { | ||||
|             ac_set_tmpfile config | ||||
|             git show "$ConfigBranch:.pman.conf" >"$config" 2>/dev/null | ||||
|             [ -s "$config" ] || die "$ConfigBranch: aucune configuration trouvée sur cette branche" || return | ||||
|             source "$config" | ||||
|             ConfigFile="$config" | ||||
|             source "$ConfigFile" | ||||
|         fi | ||||
|     elif [ -f .pman.conf ]; then | ||||
|         ConfigFile="$(pwd)/.pman.conf" | ||||
| @ -681,9 +682,7 @@ function _create_upstream_action() { | ||||
| 
 | ||||
|     # faire une copie de la configuration actuelle | ||||
|     local config; ac_set_tmpfile config | ||||
|     set -x; ls -l "$ConfigFile" #XXX | ||||
|     cp "$ConfigFile" "$config" | ||||
|     set +x #XXX | ||||
| 
 | ||||
|     einfo "Création de la branche $RefBranch" | ||||
|     git checkout --orphan "$RefBranch" || die | ||||
|  | ||||
| @ -9,4 +9,4 @@ args=( | ||||
| ) | ||||
| parse_args "$@"; set -- "${args[@]}" | ||||
| 
 | ||||
| exec "$MYDIR/ptool" -fupstream -Bdev82 -m --tech-merge ${dev74:+-a "git checkout dev74"} "$@" | ||||
| exec "$MYDIR/ptool" -fupstream -Bdev82 --tech-merge ${dev74:+-a "git checkout dev74"} "$@" | ||||
|  | ||||
| @ -221,6 +221,9 @@ if check_gitdir; then | ||||
|     set_pman_vars "$merge_dir" | ||||
|     load_branches current | ||||
|     loaded_config=1 | ||||
|     # remettre à zéro ConfigFile pour ne pas influencer le rechargement plus bas | ||||
|     oConfigFile="$ConfigFile" | ||||
|     ConfigFile= | ||||
| else | ||||
|     set_pman_vars "$merge_dir" | ||||
| fi | ||||
| @ -377,6 +380,9 @@ if [ -z "$loaded_config" -o -n "$chdir" -o -n "$ConfigFile" -o -n "$ConfigBranch | ||||
|     load_config | ||||
|     set_pman_vars "$merge_dir" | ||||
|     load_branches current | ||||
| else | ||||
|     # restaurer ConfigFile précédent | ||||
|     ConfigFile="$oConfigFile" | ||||
| fi | ||||
| resolve_should_push quiet | ||||
| 
 | ||||
|  | ||||
| @ -6,38 +6,26 @@ use nulib\cl; | ||||
| use nulib\cv; | ||||
| use nulib\exceptions; | ||||
| use nulib\output\msg; | ||||
| use nulib\php\types\vbool; | ||||
| use nulib\str; | ||||
| use PHPMailer\PHPMailer\PHPMailer; | ||||
| use PHPMailer\PHPMailer\SMTP; | ||||
| 
 | ||||
| class mailer { | ||||
|   private static function is_bool(&$value): bool { | ||||
|     if ($value === null) { | ||||
|       return false; | ||||
|     } elseif (is_bool($value)) { | ||||
|     if ($value === null) return false; | ||||
|     elseif (is_bool($value)) return true; | ||||
|     elseif (is_numeric($value)) { | ||||
|       $value = $value != 0; | ||||
|       return true; | ||||
|     } elseif (is_int($value)) { | ||||
|       $value = boolval($value); | ||||
|     } elseif (vbool::is_yes($value)) { | ||||
|       $value = true; | ||||
|       return true; | ||||
|     } elseif ($value === "" || vbool::is_no($value)) { | ||||
|       $value = false; | ||||
|       return true; | ||||
|     } else { | ||||
|       switch (strval($value)) { | ||||
|       case "": | ||||
|       case "0": | ||||
|       case "no": | ||||
|       case "off": | ||||
|       case "false": | ||||
|         $value = false; | ||||
|         return true; | ||||
|       case "1": | ||||
|       case "yes": | ||||
|       case "on": | ||||
|       case "true": | ||||
|         $value = true; | ||||
|         return true; | ||||
|       default: | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   private static function get_bool($value): bool { | ||||
| @ -120,19 +108,14 @@ class mailer { | ||||
|     $mailer->SMTPDebug = $debug; | ||||
|     # auth, username, password
 | ||||
|     $username = $params["username"] ?? null; | ||||
|     $username ??= cv::vn(getenv("NULIB_MAIL_USERNAME")); | ||||
|     $password = $params["password"] ?? null; | ||||
|     $password ??= cv::vn(getenv("NULIB_MAIL_PASSWORD")); | ||||
|     $auth = $params["auth"] ?? null; | ||||
|     $auth ??= cv::vn(getenv("NULIB_MAIL_AUTH")); | ||||
|     $auth ??= $username !== null && $password !== null; | ||||
|     $mailer->SMTPAuth = self::get_bool($auth); | ||||
|     $mailer->Username = $username; | ||||
|     $mailer->Password = $password; | ||||
|     # secure
 | ||||
|     $secure = $params["secure"] ?? null; | ||||
|     $secure ??= cv::vn(getenv("NULIB_MAIL_SECURE")); | ||||
|     $secure ??= false; | ||||
|     $secure = $params["secure"] ?? false; | ||||
|     if (self::is_bool($secure)) { | ||||
|       if (!$secure) { | ||||
|         $mailer->SMTPSecure = ""; | ||||
|  | ||||
							
								
								
									
										16
									
								
								php/src/php/time/Hour.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								php/src/php/time/Hour.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| <?php | ||||
| namespace nulib\php\time; | ||||
| 
 | ||||
| class Hour extends Time { | ||||
|   const UNIT = self::UNIT_MINUTES; | ||||
| 
 | ||||
|   const FORMAT = "%hh%M"; | ||||
| 
 | ||||
|   function format(?string $format=null): string { | ||||
|     $string = parent::format($format); | ||||
|     if (substr($string, -3) == "h00") { | ||||
|       $string = substr($string, 0, -2); | ||||
|     } | ||||
|     return $string; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										288
									
								
								php/src/php/time/Time.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								php/src/php/time/Time.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,288 @@ | ||||
| <?php | ||||
| namespace nulib\php\time; | ||||
| 
 | ||||
| use DateTimeInterface; | ||||
| use nulib\exceptions; | ||||
| use nulib\php\types\vbool; | ||||
| use nulib\php\types\vint; | ||||
| 
 | ||||
| /** | ||||
|  * Class Time: une heure allant de 0h à 24h inclus. | ||||
|  * | ||||
|  * la seule utilisation autorisée de "24h" est comme borne supérieure pour une | ||||
|  * plage horaire. | ||||
|  */ | ||||
| class Time { | ||||
|   const UNIT_HOURS = 3600; | ||||
|   const UNIT_MINUTES = 60; | ||||
|   const UNIT_SECONDS = 1; | ||||
| 
 | ||||
|   const PATTERNS = [ | ||||
|     '/^(\d+)[:.h](\d+)(?:[:.](\d+))?$/', | ||||
|     '/^(\d+)h(?:(\d+)(?:[:.](\d+))?)?$/' | ||||
|   ]; | ||||
| 
 | ||||
|   /** @var string format par défaut pour l'affichage */ | ||||
|   const FORMAT = "%H:%M:%S"; | ||||
| 
 | ||||
|   static function with($time): self { | ||||
|     if ($time instanceof static) return $time; | ||||
|     else return new static($time); | ||||
|   } | ||||
| 
 | ||||
|   static function withn($time): ?self { | ||||
|     if ($time === null) return null; | ||||
|     elseif ($time instanceof static) return $time; | ||||
|     else return new static($time); | ||||
|   } | ||||
| 
 | ||||
|   static function isa_time($time): bool { | ||||
|     if ($time === null) return false; | ||||
|     if ($time instanceof self) return true; | ||||
|     if (is_int($time)) return true; | ||||
|     if (is_string($time)) { | ||||
|       foreach (self::PATTERNS as $pattern) { | ||||
|         if (preg_match($pattern, $time)) return true; | ||||
|       } | ||||
|     } | ||||
|     if ($time instanceof DateTimeInterface) return true; | ||||
|     if (is_array($time) && count($time) == 3) return true; | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   protected static function s_now(): int { | ||||
|     $hms = date('His'); | ||||
|     return intval(substr($hms, 0, 2)) * 3600 | ||||
|       + intval(substr($hms, 2, 2)) * 60 | ||||
|       + intval(substr($hms, 4, 2)); | ||||
|   } | ||||
| 
 | ||||
|   protected static function s_get($time, int $unit=self::UNIT_SECONDS): int { | ||||
|     if ($time === null) { | ||||
|       return 0; | ||||
|     } elseif ($time instanceof self) { | ||||
|       return $time->getSeconds(); | ||||
|     } elseif (is_int($time)) { | ||||
|       return $time * $unit; | ||||
|     } elseif (is_string($time)) { | ||||
|       $matched = false; | ||||
|       foreach (self::PATTERNS as $pattern) { | ||||
|         if (preg_match($pattern, $time, $ms)) { | ||||
|           $matched = true; | ||||
|           break; | ||||
|         } | ||||
|       } | ||||
|       if ($matched) { | ||||
|         $h = $ms[1]; | ||||
|         $m = $ms[2] ?? 0; | ||||
|         $s = $ms[3] ?? 0; | ||||
|         return intval($h) * 3600 + intval($m) * 60 + intval($s); | ||||
|       } | ||||
|     } elseif ($time instanceof DateTimeInterface) { | ||||
|       $hms = $time->format('His'); | ||||
|       return intval(substr($hms, 0, 2)) * 3600 | ||||
|         + intval(substr($hms, 2, 2)) * 60 | ||||
|         + intval(substr($hms, 4, 2)); | ||||
|     } elseif (is_array($time) && count($time) == 3) { | ||||
|       [$h, $m, $s] = $time; | ||||
|       return $h * 3600 + $m * 60 + $s; | ||||
|     } | ||||
|     throw exceptions::invalid_value($time, "time"); | ||||
|   } | ||||
| 
 | ||||
|   protected static function s_adjust(int &$seconds, int $unit=self::UNIT_SECONDS, ?int $step=null): int { | ||||
|     if ($step !== null) $unit *= $step; | ||||
|     $adjust = $seconds % $unit; | ||||
|     if ($seconds < 0) $adjust = -$adjust; | ||||
|     $seconds -= $adjust; | ||||
|     return $seconds; | ||||
|   } | ||||
| 
 | ||||
|   protected static function s_wrap_start(int &$seconds): int { | ||||
|     while ($seconds < 0) $seconds += 86400; | ||||
|     if ($seconds >= 86400) $seconds %= 86400; | ||||
|     return $seconds; | ||||
|   } | ||||
| 
 | ||||
|   protected static function s_wrap_end(int &$seconds): int { | ||||
|     while ($seconds < 0) $seconds += 86400; | ||||
|     if ($seconds > 86400) $seconds %= 86400; | ||||
|     return $seconds; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * @var int la valeur de l'unité en secondes, pour le constructeur et les | ||||
|    * méthodes {@link setu()}, {@link addu()} et {@link subu()} | ||||
|    */ | ||||
|   const UNIT = self::UNIT_SECONDS; | ||||
| 
 | ||||
|   /** | ||||
|    * @var int|null un nombre d'unité dont l'heure doit être multiple. par | ||||
|    * exemple, si l'unité est la minute, une valeur 5 permet d'avoir des heures | ||||
|    * qui vont de 5 en 5 minutes (0h00, 0h05, 0h10, etc.) | ||||
|    */ | ||||
|   const STEP = null; | ||||
| 
 | ||||
|   /** @var bool s'il faut garder les heures dans la plage [0, 24h] */ | ||||
|   const WRAP = true; | ||||
| 
 | ||||
|   function __construct($time=null, ?array $params=null) { | ||||
|     $this->unit = vint::with($params["unit"] ?? static::UNIT); | ||||
|     $this->step = vint::withn($params["step"] ?? self::STEP); | ||||
|     $this->wrap = vbool::with($params["wrap"] ?? self::WRAP); | ||||
|     if ($time === null) $seconds = self::s_now(); | ||||
|     else $seconds = self::s_get($time, $this->unit); | ||||
|     $this->setSeconds($seconds); | ||||
|   } | ||||
| 
 | ||||
|   protected int $unit; | ||||
| 
 | ||||
|   protected ?int $step; | ||||
| 
 | ||||
|   protected bool $wrap; | ||||
| 
 | ||||
|   protected int $seconds; | ||||
| 
 | ||||
|   function getSeconds(): int { | ||||
|     return $this->seconds; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * mettre à jour cet objet avec le nombre de secondes spécifié | ||||
|    * | ||||
|    * le nombre effectif de secondes est calculé en tenant compte de l'unité | ||||
|    * actuelle | ||||
|    * | ||||
|    * @return int le nombre de seconde effectif, après correction | ||||
|    */ | ||||
|   protected function setSeconds(?int $seconds): int { | ||||
|     $this->seconds = $seconds ?? self::s_now(); | ||||
|     return $this->afterUpdate(); | ||||
|   } | ||||
| 
 | ||||
|   protected function afterUpdate(): int { | ||||
|     self::s_adjust($this->seconds, $this->unit, $this->step); | ||||
|     if ($this->wrap) $this->wrapEnd(); | ||||
|     return $this->seconds; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * wrapper l'heure pour la garder dans la plage [0h, 24h[ ce qui la rend | ||||
|    * propice à l'utilisation comme borne inférieure d'une période | ||||
|    */ | ||||
|   function wrapStart(): self { | ||||
|     self::s_wrap_start($this->seconds); | ||||
|     return $this; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * wrapper l'heure pour la garder dans la plage [0h, 24h] ce qui la rend | ||||
|    * propice à l'utilisation comme borne supérieure d'une période | ||||
|    */ | ||||
|   function wrapEnd(): self { | ||||
|     self::s_wrap_end($this->seconds); | ||||
|     return $this; | ||||
|   } | ||||
| 
 | ||||
|   /** formatter cette heure pour affichage */ | ||||
|   function format(?string $format=null): string { | ||||
|     if ($format === null) $format = static::FORMAT; | ||||
|     $v = $this->seconds; | ||||
|     $h = intdiv($v, 3600); $v = $v % 3600; | ||||
|     $m = intdiv($v, 60); | ||||
|     $s = $v % 60; | ||||
|     $searches = [ | ||||
|       "%H", "%h", | ||||
|       "%M", "%m", | ||||
|       "%S", "%s", | ||||
|       "%%", | ||||
|     ]; | ||||
|     $replaces = [ | ||||
|       sprintf("%02u", $h), strval($h), | ||||
|       sprintf("%02u", $m), strval($m), | ||||
|       sprintf("%02u", $s), strval($s), | ||||
|       "%", | ||||
|     ]; | ||||
|     return str_replace($searches, $replaces, $format); | ||||
|   } | ||||
| 
 | ||||
|   function __toString(): string { | ||||
|     return $this->format(); | ||||
|   } | ||||
| 
 | ||||
|   /** @return int le nombre d'unités */ | ||||
|   function getu(): int { | ||||
|     return intdiv($this->seconds, $this->unit); | ||||
|   } | ||||
| 
 | ||||
|   /** créer une nouvelle heure avec le nombre d'unités spécifiées */ | ||||
|   function setu(int $count): self { | ||||
|     $this->setSeconds($count * $this->unit); | ||||
|     return $this; | ||||
|   } | ||||
| 
 | ||||
|   /** créer une nouvelle heure en ajoutant à cette heure le nombre d'unités spécifiées */ | ||||
|   function addu(int $count=1): self { | ||||
|     $count *= $this->unit; | ||||
|     if ($this->step !== null) $count *= $this->step; | ||||
|     $this->setSeconds($this->seconds + $count); | ||||
|     return $this; | ||||
|   } | ||||
| 
 | ||||
|   /** créer une nouvelle heure en soustrayant à cette heure le nombre d'unités spécifiées */ | ||||
|   function subu(int $count=1): self { | ||||
|     $count *= $this->unit; | ||||
|     if ($this->step !== null) $count *= $this->step; | ||||
|     $this->setSeconds($this->seconds - $count); | ||||
|     return $this; | ||||
|   } | ||||
| 
 | ||||
|   /** forcer cette heure à l'heure spécifiée */ | ||||
|   function set($time): self { | ||||
|     if ($time === null) $seconds = self::s_now(); | ||||
|     else $seconds = self::with($time)->getSeconds(); | ||||
|     $this->setSeconds($seconds); | ||||
|     return $this; | ||||
|   } | ||||
| 
 | ||||
|   /** ajouter à cette heure l'heure spécifiée */ | ||||
|   function add($time): self { | ||||
|     if ($time !== null) { | ||||
|       $this->setSeconds($this->seconds + self::with($time)->getSeconds()); | ||||
|     } | ||||
|     return $this; | ||||
|   } | ||||
| 
 | ||||
|   /** soustraire à cette heure l'heure spécifiée */ | ||||
|   function sub($time): self { | ||||
|     if ($time !== null) { | ||||
|       $this->setSeconds($this->seconds - self::with($time)->getSeconds()); | ||||
|     } | ||||
|     return $this; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * comparer avec l'heure spécifiée. retourner une valeur négative, égale à | ||||
|    * zéro ou positive suivant le résultat de la comparaison | ||||
|    */ | ||||
|   function compare($time): int { | ||||
|     if ($time === null) return 1; | ||||
|     else return $this->seconds - self::with($time)->getSeconds(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * tester si cette heure est avant ou égale à l'heure spécifiée | ||||
|    */ | ||||
|   function before($other): bool { | ||||
|     if ($other === null) return false; | ||||
|     else return $this->seconds <= self::with($other)->getSeconds(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * tester si cette heure est après ou égale à l'heure spécifiée | ||||
|    */ | ||||
|   function after($other): bool { | ||||
|     if ($other === null) return true; | ||||
|     else return $this->seconds >= self::with($other)->getSeconds(); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										58
									
								
								php/src/php/types/_schema.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								php/src/php/types/_schema.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| use nulib\str; | ||||
| 
 | ||||
| class _schema { | ||||
|   /** @var array association type simple / vclass */ | ||||
|   const VCLASSES = [ | ||||
|     "rawstring" => vrawstring::class, | ||||
|     "string" => vstring::class, | ||||
|     "text" => vtext::class, | ||||
|     "bool" => vbool::class, | ||||
|     "int" => vint::class, | ||||
|     "float" => vfloat::class, | ||||
|     "array" => varray::class, | ||||
|     "func" => vfunc::class, | ||||
|     "raw" => vraw::class, | ||||
|     "mixed" => vmixed::class, | ||||
|     "key" => vkey::class, | ||||
|     "pkey" => vpkey::class, | ||||
|     "content" => vcontent::class, | ||||
|     "datetime" => vdatetime::class, | ||||
|     "date" => vdate::class, | ||||
|     "time" => vtime::class, | ||||
|   ]; | ||||
| 
 | ||||
|   static function get_types($schema, &$default = null, ?bool &$required = null): array { | ||||
|     if (is_array($schema)) { | ||||
|       $types = $schema["type"] ?? $schema[0] ?? null; | ||||
|       $default = $schema["default"] ?? $schema[1] ?? null; | ||||
|       $required = vbool::with($schema["required"] ?? false); | ||||
|     } elseif (is_string($schema)) { | ||||
|       $types = $schema; | ||||
|       $default = null; | ||||
|       $required = false; | ||||
|     } else { | ||||
|       throw exceptions::invalid_value($schema, "schema"); | ||||
|     } | ||||
|     if (is_string($types)) { | ||||
|       $types = explode(",", $types); | ||||
|     } elseif (!is_array($types)) { | ||||
|       throw exceptions::invalid_value($types, "types"); | ||||
|     } | ||||
|     return $types; | ||||
|   } | ||||
| 
 | ||||
|   static function get_vclass(array $types, ?bool &$nullable): ?string { | ||||
|     foreach ($types as $type) { | ||||
|       $vclass = self::VCLASSES[$type] ?? null; | ||||
|       if ($vclass !== null) { | ||||
|         $nullable = str::del_prefix($type, "?"); | ||||
|         return $vclass; | ||||
|       } | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										75
									
								
								php/src/php/types/assoc.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								php/src/php/types/assoc.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| 
 | ||||
| /** | ||||
|  * Class assoc: gestion simplifiée de schémas associatifs | ||||
|  * | ||||
|  * seuls les types simples sont reconnus | ||||
|  */ | ||||
| class assoc { | ||||
|   /** indiquer si $array est conforme au schéma */ | ||||
|   public static function check_schema(?array $array, array $schema, bool $strict = false): bool { | ||||
|     foreach ($schema as $key => $kschema) { | ||||
|       $types = _schema::get_types($kschema, $default, $required); | ||||
|       $exists = array_key_exists($key, $array); | ||||
|       if (!$exists) { | ||||
|         if ($required) return false; | ||||
|         else continue; | ||||
|       } | ||||
|       $vclass = _schema::get_vclass($types, $nullable); | ||||
|       # le test échoue si le type n'est pas supporté
 | ||||
|       if ($vclass === null) return false; | ||||
|       $value = $array[$key]; | ||||
|       if ($value === null) { | ||||
|         if (!$nullable) return false; | ||||
|       } else { | ||||
|         if (!$vclass::isa($value, $strict)) return false; | ||||
|       } | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * s'assurer que $array est conforme au schéma | ||||
|    * - les clés ne sont pas créées si elles n'existent pas, sauf si la valeur | ||||
|    * est requise ou si une valeur par défaut non nulle est fournie | ||||
|    */ | ||||
|   public static function ensure_schema(&$array, array $schema): bool { | ||||
|     $ensured = true; | ||||
|     foreach ($schema as $key => $kschema) { | ||||
|       $types = _schema::get_types($kschema, $default, $required); | ||||
| 
 | ||||
|       $exists = array_key_exists($key, $array); | ||||
|       if (!$exists) { | ||||
|         if ($required) { | ||||
|           if ($default !== null) { | ||||
|             $array[$key] = $default; | ||||
|           } else { | ||||
|             throw exceptions::missing_value(null, "array", "$key est obligatoire"); | ||||
|           } | ||||
|         } elseif ($default !== null) { | ||||
|           $array[$key] = $default; | ||||
|         } | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       $vclass = _schema::get_vclass($types, $nullable); | ||||
|       # le test échoue si le type n'est pas supporté
 | ||||
|       if ($vclass === null) { | ||||
|         $ensured = false; | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       $value = $array[$key]; | ||||
|       if ($nullable) { | ||||
|         $array[$key] = $vclass::withn($value); | ||||
|       } else { | ||||
|         if ($value === null) $value = $default; | ||||
|         $array[$key] = $vclass::with($value); | ||||
|       } | ||||
|     } | ||||
|     return $ensured; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										34
									
								
								php/src/php/types/scalar.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								php/src/php/types/scalar.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| use nulib\str; | ||||
| 
 | ||||
| /** | ||||
|  * Class scalar: gestion simplifiée de schémas de valeurs simples | ||||
|  */ | ||||
| class scalar { | ||||
|   /** indiquer si $value est conforme au schéma */ | ||||
|   static function check_schema($value, $schema, bool $strict=false): bool { | ||||
|     $types = _schema::get_types($schema); | ||||
|     $vclass = _schema::get_vclass($types, $nullable); | ||||
|     # le test échoue si le type n'est pas supporté
 | ||||
|     if ($vclass === null) return false; | ||||
|     if ($value === null) return $nullable; | ||||
|     return $vclass::isa($value, $strict); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure_schema(&$value, $schema): bool { | ||||
|     $types = _schema::get_types($schema, $default); | ||||
|     $vclass = _schema::get_vclass($types, $nullable); | ||||
|     # la conversion échoue si le type n'est pas supporté
 | ||||
|     if ($vclass === null) return false; | ||||
|     if ($nullable) { | ||||
|       $value = $vclass::withn($value); | ||||
|     } else { | ||||
|       if ($value === null) $value = $default; | ||||
|       $value = $vclass::with($value); | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
| } | ||||
| @ -2,10 +2,19 @@ | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\cl; | ||||
| use nulib\exceptions; | ||||
| 
 | ||||
| class varray { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return is_array($value); | ||||
|     else return is_scalar($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$array): void { | ||||
|     if (!is_array($array)) $array = cl::with($array); | ||||
|     if (is_array($array)) return; | ||||
|     if ($array === null || $array === false) $array = []; | ||||
|     elseif (is_scalar($array)) $array = cl::with($array); | ||||
|     else throw exceptions::invalid_value($array, "array"); | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$array): void { | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| 
 | ||||
| class vbool { | ||||
|   /** liste de valeurs chaines à considérer comme 'OUI' */ | ||||
|   public const YES_VALUES = [ | ||||
| @ -30,12 +32,25 @@ class vbool { | ||||
|     return in_array($value, self::NO_VALUES, true); | ||||
|   } | ||||
| 
 | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return is_bool($value); | ||||
|     elseif (is_string($value)) return self::is_yes($value) || self::is_no($value); | ||||
|     else return is_scalar($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$bool): void { | ||||
|     if (is_string($bool)) { | ||||
|     if (is_bool($bool)) return; | ||||
|     if ($bool === null) { | ||||
|       $bool = false; | ||||
|     } elseif (is_string($bool)) { | ||||
|       if (self::is_yes($bool)) $bool = true; | ||||
|       elseif (self::is_no($bool)) $bool = false; | ||||
|       else throw exceptions::invalid_value($bool, "boolean"); | ||||
|     } elseif (is_scalar($bool)) { | ||||
|       $bool = boolval($bool); | ||||
|     } else { | ||||
|       throw exceptions::invalid_value($bool, "boolean"); | ||||
|     } | ||||
|     if (!is_bool($bool)) $bool = boolval($bool); | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$bool): void { | ||||
|  | ||||
| @ -1,10 +1,28 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| use nulib\php\content\IContent; | ||||
| use nulib\php\content\IPrintable; | ||||
| 
 | ||||
| class vcontent { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return is_array($value) || is_string($value); | ||||
|     return is_array($value) || is_scalar($value) || | ||||
|       $value instanceof IContent || $value instanceof IPrintable; | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$content): void { | ||||
|     if ($content === null || $content === false) $content = []; | ||||
|     elseif (!is_string($content) && !is_array($content)) $content = strval($content); | ||||
|     if (is_array($content) || is_string($content)) return; | ||||
|     if ($content === null || $content === false) { | ||||
|       $content = []; | ||||
|     } elseif (is_scalar($content)) { | ||||
|       $content = [$content]; | ||||
|     } elseif ($content instanceof IContent || $content instanceof IPrintable) { | ||||
|       $content = [$content]; | ||||
|     } else { | ||||
|       throw exceptions::invalid_value($content, "content"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$content): void { | ||||
|  | ||||
							
								
								
									
										29
									
								
								php/src/php/types/vdate.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								php/src/php/types/vdate.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\php\time\Date; | ||||
| 
 | ||||
| class vdate { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return $value instanceof Date; | ||||
|     else return Date::isa_date($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$date): void { | ||||
|     $date = Date::with($date); | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$date): void { | ||||
|     $date = Date::withn($date); | ||||
|   } | ||||
| 
 | ||||
|   static function with($value): Date { | ||||
|     self::ensure($value); | ||||
|     return $value; | ||||
|   } | ||||
| 
 | ||||
|   static function withn($value): ?Date { | ||||
|     self::ensuren($value); | ||||
|     return $value; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										29
									
								
								php/src/php/types/vdatetime.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								php/src/php/types/vdatetime.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\php\time\DateTime; | ||||
| 
 | ||||
| class vdatetime { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return $value instanceof DateTime; | ||||
|     else return DateTime::isa_datetime($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$datetime): void { | ||||
|     $datetime = DateTime::with($datetime); | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$datetime): void { | ||||
|     $datetime = DateTime::withn($datetime); | ||||
|   } | ||||
| 
 | ||||
|   static function with($value): DateTime { | ||||
|     self::ensure($value); | ||||
|     return $value; | ||||
|   } | ||||
| 
 | ||||
|   static function withn($value): ?DateTime { | ||||
|     self::ensuren($value); | ||||
|     return $value; | ||||
|   } | ||||
| } | ||||
| @ -1,9 +1,19 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| 
 | ||||
| class vfloat { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return is_float($value); | ||||
|     else return is_numeric($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$float): void { | ||||
|     if (!is_float($float)) $float = floatval($float); | ||||
|     if (is_float($float)) return; | ||||
|     if ($float === null || $float === false) $float = 0.0; | ||||
|     elseif (is_numeric($float)) $float = floatval($float); | ||||
|     else throw exceptions::invalid_value($float, "float"); | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$float): void { | ||||
|  | ||||
| @ -4,6 +4,11 @@ namespace nulib\php\types; | ||||
| use nulib\php\func; | ||||
| 
 | ||||
| class vfunc { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return $value instanceof func; | ||||
|     else return func::is_callable($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$func): void { | ||||
|     $func = func::ensure($func); | ||||
|   } | ||||
|  | ||||
| @ -1,9 +1,19 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| 
 | ||||
| class vint { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return is_int($value); | ||||
|     else return is_numeric($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$int): void { | ||||
|     if (!is_int($int)) $int = intval($int); | ||||
|     if (is_int($int)) return; | ||||
|     if ($int === null || $int === false) $int = 0.0; | ||||
|     elseif (is_numeric($int)) $int = intval($int); | ||||
|     else throw exceptions::invalid_value($int, "int"); | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$int): void { | ||||
|  | ||||
| @ -1,11 +1,20 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| 
 | ||||
| class vkey { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return is_int($value) || is_string($value); | ||||
|     else return is_scalar($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$key): void { | ||||
|     if (is_int($key) || is_string($key)) return; | ||||
|     if ($key === null) $key = ""; | ||||
|     elseif ($key === false) $key = 0; | ||||
|     elseif (!is_string($key) && !is_int($key)) $key = strval($key); | ||||
|     elseif (is_scalar($key)) $key = strval($key); | ||||
|     else throw exceptions::invalid_value($key, "key"); | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$key): void { | ||||
|  | ||||
							
								
								
									
										22
									
								
								php/src/php/types/vmixed.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								php/src/php/types/vmixed.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| class vmixed { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$mixed): void { | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$mixed): void { | ||||
|   } | ||||
| 
 | ||||
|   static function with($value) { | ||||
|     return $value; | ||||
|   } | ||||
| 
 | ||||
|   static function withn($value) { | ||||
|     return $value; | ||||
|   } | ||||
| } | ||||
| @ -1,17 +1,28 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| 
 | ||||
| class vpkey { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return is_array($value) || is_int($value) || is_string($value); | ||||
|     else return is_array($value) || is_scalar($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$pkey): void { | ||||
|     if ($pkey === null) $pkey = ""; | ||||
|     elseif ($pkey === false) $pkey = 0; | ||||
|     elseif (!is_string($pkey) && !is_int($pkey) && !is_array($pkey)) $pkey = strval($pkey); | ||||
|     if (is_array($pkey)) { | ||||
|       foreach ($pkey as &$key) { | ||||
|         vkey::ensure($key); | ||||
|       }; | ||||
|       unset($key); | ||||
|       return; | ||||
|     } elseif (is_int($pkey) || is_string($pkey)) { | ||||
|       return; | ||||
|     } | ||||
|     if ($pkey === null) $pkey = ""; | ||||
|     elseif ($pkey === false) $pkey = 0; | ||||
|     elseif (is_scalar($pkey)) $pkey = strval($pkey); | ||||
|     else throw exceptions::invalid_value($pkey, "pkey"); | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$pkey): void { | ||||
|  | ||||
							
								
								
									
										22
									
								
								php/src/php/types/vraw.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								php/src/php/types/vraw.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| class vraw { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$raw): void { | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$raw): void { | ||||
|   } | ||||
| 
 | ||||
|   static function with($value) { | ||||
|     return $value; | ||||
|   } | ||||
| 
 | ||||
|   static function withn($value) { | ||||
|     return $value; | ||||
|   } | ||||
| } | ||||
| @ -1,6 +1,7 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\exceptions; | ||||
| use nulib\str; | ||||
| 
 | ||||
| class vrawstring { | ||||
| @ -9,8 +10,19 @@ class vrawstring { | ||||
|   /** @var bool faut-il normaliser les caractères fin de ligne */ | ||||
|   const NORM_NL = false; | ||||
| 
 | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return is_string($value); | ||||
|     else return is_scalar($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$string): void { | ||||
|     if (!is_string($string)) $string = strval($string); | ||||
|     if (!is_string($string)) { | ||||
|       if (is_scalar($string)) { | ||||
|         $string = strval($string); | ||||
|       } else { | ||||
|         throw exceptions::invalid_value($string, "string"); | ||||
|       } | ||||
|     } | ||||
|     if (static::TRIM) $string = trim($string); | ||||
|     if (static::NORM_NL) $string = str::norm_nl($string); | ||||
|   } | ||||
|  | ||||
							
								
								
									
										30
									
								
								php/src/php/types/vtime.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								php/src/php/types/vtime.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\php\time\DateTime; | ||||
| use nulib\php\time\Time; | ||||
| 
 | ||||
| class vtime { | ||||
|   static function isa($value, bool $strict=false) : bool { | ||||
|     if ($strict) return $value instanceof Time; | ||||
|     else return Time::isa_time($value); | ||||
|   } | ||||
| 
 | ||||
|   static function ensure(&$time): void { | ||||
|     $time = Time::with($time); | ||||
|   } | ||||
| 
 | ||||
|   static function ensuren(&$time): void { | ||||
|     $time = Time::withn($time); | ||||
|   } | ||||
| 
 | ||||
|   static function with($value): Time { | ||||
|     self::ensure($value); | ||||
|     return $value; | ||||
|   } | ||||
| 
 | ||||
|   static function withn($value): ?Time { | ||||
|     self::ensuren($value); | ||||
|     return $value; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										60
									
								
								php/tests/php/time/HourTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								php/tests/php/time/HourTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| <?php | ||||
| namespace nulib\php\time; | ||||
| 
 | ||||
| use nulib\tests\TestCase; | ||||
| use nulib\ValueException; | ||||
| 
 | ||||
| class HourTest extends TestCase { | ||||
|   function testParse() { | ||||
|     self::assertSame("8h", strval(new Hour("08:00:00"))); | ||||
|     self::assertSame("8h", strval(new Hour("8:0"))); | ||||
|     self::assertSame("8h", strval(new Hour("8.0"))); | ||||
|     self::assertSame("8h", strval(new Hour("8h"))); | ||||
| 
 | ||||
|     self::assertSame("8h15", strval(new Hour("08:15:00"))); | ||||
|     self::assertSame("8h15", strval(new Hour("8:15"))); | ||||
|     self::assertSame("8h15", strval(new Hour("8.15"))); | ||||
|     self::assertSame("8h15", strval(new Hour("8h15"))); | ||||
| 
 | ||||
|     self::assertSame("8h15", strval(new Hour("08:15:23"))); | ||||
|     self::assertSame("8h15", strval(new Hour("8:15.23"))); | ||||
|     self::assertSame("8h15", strval(new Hour("8.15.23"))); | ||||
|     self::assertSame("8h15", strval(new Hour("8h15.23"))); | ||||
| 
 | ||||
|     self::assertSame("31h11", strval(new Hour("30:70:80", [ | ||||
|       "wrap" => false, | ||||
|     ]))); | ||||
|     self::assertSame("7h11", strval(new Hour("30:70:80"))); | ||||
| 
 | ||||
|     self::assertException(ValueException::class, function() { | ||||
|       return strval(new Hour("bad format")); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   function testFormat() { | ||||
|     self::assertSame("0h", (new Hour(0))->format()); | ||||
|     self::assertSame("0h56", (new Hour(56))->format()); | ||||
|     self::assertSame("2h", (new Hour(120))->format()); | ||||
|     self::assertSame("23h59", (new Hour(1439))->format()); | ||||
|     self::assertSame("24h", (new Hour(1440))->format()); | ||||
|     self::assertSame("0h01", (new Hour(1441))->format()); | ||||
|   } | ||||
| 
 | ||||
|   function testStep() { | ||||
|     $h = new Hour(null, [ | ||||
|       "step" => 5, | ||||
|     ]); | ||||
|     $h->setu(10); self::assertSame("0h10", strval($h)); | ||||
|     $h->setu(12); self::assertSame("0h10", strval($h)); | ||||
|     $h->setu(15); self::assertSame("0h15", strval($h)); | ||||
|     $h->setu(17); self::assertSame("0h15", strval($h)); | ||||
| 
 | ||||
|     $h->set("8h"); | ||||
|     $h->addu(); self::assertSame("8h05", strval($h)); | ||||
|     $h->addu(); self::assertSame("8h10", strval($h)); | ||||
|     $h->addu(); self::assertSame("8h15", strval($h)); | ||||
|     $h->subu(); self::assertSame("8h10", strval($h)); | ||||
|     $h->subu(); self::assertSame("8h05", strval($h)); | ||||
|     $h->subu(); self::assertSame("8h", strval($h)); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										74
									
								
								php/tests/php/time/TimeTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								php/tests/php/time/TimeTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | ||||
| <?php | ||||
| namespace nulib\php\time; | ||||
| 
 | ||||
| use nulib\tests\TestCase; | ||||
| use nulib\ValueException; | ||||
| 
 | ||||
| class TimeTest extends TestCase { | ||||
|   function testParse() { | ||||
|     self::assertSame("08:00:00", strval(new Time("08:00:00"))); | ||||
|     self::assertSame("08:00:00", strval(new Time("8:0"))); | ||||
|     self::assertSame("08:00:00", strval(new Time("8.0"))); | ||||
|     self::assertSame("08:00:00", strval(new Time("8h"))); | ||||
| 
 | ||||
|     self::assertSame("08:15:00", strval(new Time("08:15:00"))); | ||||
|     self::assertSame("08:15:00", strval(new Time("8:15"))); | ||||
|     self::assertSame("08:15:00", strval(new Time("8.15"))); | ||||
|     self::assertSame("08:15:00", strval(new Time("8h15"))); | ||||
| 
 | ||||
|     self::assertSame("08:15:23", strval(new Time("08:15:23"))); | ||||
|     self::assertSame("08:15:23", strval(new Time("8:15.23"))); | ||||
|     self::assertSame("08:15:23", strval(new Time("8.15.23"))); | ||||
|     self::assertSame("08:15:23", strval(new Time("8h15.23"))); | ||||
| 
 | ||||
|     self::assertSame("31:11:20", strval(new Time("30:70:80", [ | ||||
|       "wrap" => false, | ||||
|     ]))); | ||||
|     self::assertSame("07:11:20", strval(new Time("30:70:80"))); | ||||
| 
 | ||||
|     self::assertException(ValueException::class, function() { | ||||
|       return strval(new Time("bad format")); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   function testGetu() { | ||||
|     self::assertSame(0, (new Time(0))->getu()); | ||||
|     self::assertSame(86399, (new Time(-1))->getu()); | ||||
|     self::assertSame(1, (new Time(1))->getu()); | ||||
|     self::assertSame(120, (new Time(120))->getu()); | ||||
|     self::assertSame(86400, (new Time(86400))->getu()); | ||||
|     self::assertSame(0, (new Time(-86400))->getu()); | ||||
|   } | ||||
| 
 | ||||
|   function testAddu() { | ||||
|     $t = new Time(0); | ||||
|     $t->addu(0); self::assertSame(0, $t->getu()); | ||||
|     $t->addu(10); self::assertSame(10, $t->getu()); | ||||
|     $t->addu(10); self::assertSame(20, $t->getu()); | ||||
|     $t->addu(100); self::assertSame(120, $t->getu()); | ||||
|     $t->addu(86280); self::assertSame(86400, $t->getu()); | ||||
|     $t->addu(86400); self::assertSame(0, $t->getu()); | ||||
|     $t->addu(-86400); self::assertSame(0, $t->getu()); | ||||
|   } | ||||
| 
 | ||||
|   function testSubu() { | ||||
|     $t = new Time(0); | ||||
|     $t->subu(-86400); self::assertSame(86400, $t->getu()); | ||||
|     $t->subu(86400); self::assertSame(0, $t->getu()); | ||||
|      | ||||
|     $t = new Time(120); | ||||
|     $t->subu(100); self::assertSame(20, $t->getu()); | ||||
|     $t->subu(10); self::assertSame(10, $t->getu()); | ||||
|     $t->subu(10); self::assertSame(0, $t->getu()); | ||||
|     $t->subu(0); self::assertSame(0, $t->getu()); | ||||
|   } | ||||
| 
 | ||||
|   function testFormat() { | ||||
|     self::assertSame("00:00:00", (new Time(0))->format()); | ||||
|     self::assertSame("00:00:56", (new Time(56))->format()); | ||||
|     self::assertSame("00:02:00", (new Time(120))->format()); | ||||
|     self::assertSame("23:59:59", (new Time(86399))->format()); | ||||
|     self::assertSame("24:00:00", (new Time(86400))->format()); | ||||
|     self::assertSame("00:00:01", (new Time(86401))->format()); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										88
									
								
								php/tests/php/types/assocTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								php/tests/php/types/assocTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\tests\TestCase; | ||||
| use nulib\ValueException; | ||||
| 
 | ||||
| class assocTest extends TestCase { | ||||
|   static function assertEnsureOk(array $schema, ?array $input, ?array $output) { | ||||
|     assoc::ensure_schema($input, $schema); | ||||
|     self::assertSame($output, $input); | ||||
|   } | ||||
| 
 | ||||
|   static function assertEnsureFail(array $schema, ?array $input, ?array $output) { | ||||
|     self::assertException(ValueException::class, function() use ($input, $schema) { | ||||
|       assoc::ensure_schema($input, $schema); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   function testEnsureSchema() { | ||||
|     self::assertEnsureOk([ | ||||
|       "string" => "string", | ||||
|       "int" => "int", | ||||
|     ], [ | ||||
|       "string" => 5, | ||||
|       "int" => "42", | ||||
|     ], [ | ||||
|       "string" => "5", | ||||
|       "int" => 42, | ||||
|     ]); | ||||
|   } | ||||
| 
 | ||||
|   const SCHEMA_S = ["s" => "string"]; | ||||
|   const SCHEMA_SD = ["s" => ["string", null]]; | ||||
|   const SCHEMA_SND = ["s" => ["string", "not null"]]; | ||||
|   const SCHEMA_RS = ["s" => ["string", "required" => true]]; | ||||
|   const SCHEMA_RSD = ["s" => ["string", null, "required" => true]]; | ||||
|   const SCHEMA_RSND = ["s" => ["string", "not null", "required" => true]]; | ||||
|   const SCHEMA_NS = ["s" => "?string"]; | ||||
|   const SCHEMA_NSD = ["s" => ["?string", null]]; | ||||
|   const SCHEMA_NSND = ["s" => ["?string", "not null"]]; | ||||
|   const SCHEMA_NRS = ["s" => ["?string", "required" => true]]; | ||||
|   const SCHEMA_NRSD = ["s" => ["?string", null, "required" => true]]; | ||||
|   const SCHEMA_NRSND = ["s" => ["?string", "not null", "required" => true]]; | ||||
| 
 | ||||
|   function testEnsureSchema2() { | ||||
|     self::assertEnsureOk(self::SCHEMA_S,   [], []); | ||||
|     self::assertEnsureFail(self::SCHEMA_S, ["s" => null], ["s" => null]); | ||||
|     self::assertEnsureOk(self::SCHEMA_S,   ["s" => "not null"], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NS,  [], []); | ||||
|     self::assertEnsureOk(self::SCHEMA_NS,  ["s" => null], ["s" => null]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NS,  ["s" => "not null"], ["s" => "not null"]); | ||||
| 
 | ||||
|     self::assertEnsureOk(self::SCHEMA_SD,   [], []); | ||||
|     self::assertEnsureFail(self::SCHEMA_SD, ["s" => null], ["s" => null]); | ||||
|     self::assertEnsureOk(self::SCHEMA_SD,   ["s" => "not null"], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NSD,  [], []); | ||||
|     self::assertEnsureOk(self::SCHEMA_NSD,  ["s" => null], ["s" => null]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NSD,  ["s" => "not null"], ["s" => "not null"]); | ||||
| 
 | ||||
|     self::assertEnsureOk(self::SCHEMA_SND,  [], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_SND,  ["s" => null], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_SND,  ["s" => "not null"], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NSND, [], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NSND, ["s" => null], ["s" => null]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NSND, ["s" => "not null"], ["s" => "not null"]); | ||||
| 
 | ||||
|     self::assertEnsureFail(self::SCHEMA_RS,  [], []); | ||||
|     self::assertEnsureFail(self::SCHEMA_RS,  ["s" => null], []); | ||||
|     self::assertEnsureOk(self::SCHEMA_RS,    ["s" => "not null"], ["s" => "not null"]); | ||||
|     self::assertEnsureFail(self::SCHEMA_NRS, [], []); | ||||
|     self::assertEnsureOk(self::SCHEMA_NRS,   ["s" => null], ["s" => null]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NRS,   ["s" => "not null"], ["s" => "not null"]); | ||||
| 
 | ||||
|     self::assertEnsureFail(self::SCHEMA_RSD, [], []); | ||||
|     self::assertEnsureFail(self::SCHEMA_RSD, ["s" => null], []); | ||||
|     self::assertEnsureOk(self::SCHEMA_RSD, ["s" => "not null"], ["s" => "not null"]); | ||||
|     self::assertEnsureFail(self::SCHEMA_NRSD, [], []); | ||||
|     self::assertEnsureOk(self::SCHEMA_NRSD, ["s" => null], ["s" => null]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NRSD, ["s" => "not null"], ["s" => "not null"]); | ||||
| 
 | ||||
|     self::assertEnsureOk(self::SCHEMA_RSND, [], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_RSND, ["s" => null], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_RSND, ["s" => "not null"], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NRSND, [], ["s" => "not null"]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NRSND, ["s" => null], ["s" => null]); | ||||
|     self::assertEnsureOk(self::SCHEMA_NRSND, ["s" => "not null"], ["s" => "not null"]); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										60
									
								
								php/tests/php/types/scalarTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								php/tests/php/types/scalarTest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| <?php | ||||
| namespace nulib\php\types; | ||||
| 
 | ||||
| use nulib\tests\TestCase; | ||||
| use nulib\ValueException; | ||||
| 
 | ||||
| class scalarTest extends TestCase { | ||||
|   function testCheckSchema() { | ||||
|     self::assertTrue(scalar::check_schema(5, "int")); | ||||
|     self::assertTrue(scalar::check_schema(5, "string")); | ||||
|     self::assertTrue(scalar::check_schema(5, "float")); | ||||
| 
 | ||||
|     self::assertTrue(scalar::check_schema(5, "int", true)); | ||||
|     self::assertFalse(scalar::check_schema(5, "string", true)); | ||||
|     self::assertFalse(scalar::check_schema(5, "float", true)); | ||||
| 
 | ||||
|     self::assertTrue(scalar::check_schema("5", "int")); | ||||
|     self::assertTrue(scalar::check_schema("5", "string")); | ||||
|     self::assertTrue(scalar::check_schema("5", "float")); | ||||
| 
 | ||||
|     self::assertFalse(scalar::check_schema("5", "int", true)); | ||||
|     self::assertTrue(scalar::check_schema("5", "string", true)); | ||||
|     self::assertFalse(scalar::check_schema("5", "float", true)); | ||||
| 
 | ||||
|     self::assertFalse(scalar::check_schema("bad format", "int")); | ||||
|   } | ||||
| 
 | ||||
|   function testEnsureSchema() { | ||||
|     $v = 5; scalar::ensure_schema($v, "int"); | ||||
|     self::assertSame(5, $v); | ||||
|     $v = "5"; scalar::ensure_schema($v, "int"); | ||||
|     self::assertSame(5, $v); | ||||
|     $v = "5.0"; scalar::ensure_schema($v, "int"); | ||||
|     self::assertSame(5, $v); | ||||
|     $v = 5.0; scalar::ensure_schema($v, "int"); | ||||
|     self::assertSame(5, $v); | ||||
|      | ||||
|     $v = 5; scalar::ensure_schema($v, "string"); | ||||
|     self::assertSame("5", $v); | ||||
|     $v = "5"; scalar::ensure_schema($v, "string"); | ||||
|     self::assertSame("5", $v); | ||||
|     $v = "5.0"; scalar::ensure_schema($v, "string"); | ||||
|     self::assertSame("5.0", $v); | ||||
|     $v = 5.0; scalar::ensure_schema($v, "string"); | ||||
|     self::assertSame("5", $v); | ||||
| 
 | ||||
|     $v = 5; scalar::ensure_schema($v, "float"); | ||||
|     self::assertSame(5.0, $v); | ||||
|     $v = "5"; scalar::ensure_schema($v, "float"); | ||||
|     self::assertSame(5.0, $v); | ||||
|     $v = "5.0"; scalar::ensure_schema($v, "float"); | ||||
|     self::assertSame(5.0, $v); | ||||
|     $v = 5.0; scalar::ensure_schema($v, "float"); | ||||
|     self::assertSame(5.0, $v); | ||||
| 
 | ||||
|     self::assertException(ValueException::class, function() { | ||||
|       $v = "bad format"; scalar::ensure_schema($v, "int"); | ||||
|     }); | ||||
|   } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user