juphyter

Family compatibility

Verification

Scope

The full PHP test suite, including the table and chart formatters, with the current phibble, phplyr, and phiz releases installed.

References

Versions
PHP 8.5.10, phibble 0.5.3, phplyr 0.4.6, phiz 0.5.2, vl-convert vl-convert 1.9.0

Method

Pest runs in a copy of the tested commit with the three packages required from Packagist.

Check
End-to-end run with the external program
Recorded
2026-11-01, PHP 8.5.10, macOS 27.0.1 (arm64), commit 46349a3

Tolerances

exact equality

Applies to: Asserted values and output

x: package value; r: reference value.

Results

784 comparisons in 33 cases: 784 pass, 0 fail, 0 skipped.

By case

Results by case
Case Comparisons Status
Engine/ChannelTest 25 pass
Engine/EngineTest 61 pass
Engine/IdleTest 3 pass
Engine/ProjectTest 14 pass
Unit/Console/ApplicationTest 25 pass
Unit/Console/OptionsTest 15 pass
Unit/Console/ReferenceTest 5 pass
Unit/Display/ChartFormatterTest 22 pass
Unit/Display/DisplayFunctionTest 7 pass
Unit/Display/DumperTest 23 pass
Unit/Display/FallbackFormattersTest 10 pass
Unit/Display/MimeBundleTest 10 pass
Unit/Display/NoSiblingAtCompileTimeTest 17 pass
Unit/Display/RegistryTest 24 pass
Unit/Display/TableFormatterTest 13 pass
Unit/Display/TableRendererTest 26 pass
Unit/Display/UserTypesTest 12 pass
Unit/Engine/CleanerTest 99 pass
Unit/Engine/ExecutorTest 70 pass
Unit/Engine/SessionTest 24 pass
Unit/Engine/TracebackTest 27 pass
Unit/Install/DoctorCommandTest 20 pass
Unit/Install/InstallCommandTest 66 pass
Unit/Install/JupyterPathsTest 18 pass
Unit/Install/KernelSpecTest 27 pass
Unit/Install/PharTest 15 pass
Unit/Install/PythonProbeTest 23 pass
Unit/Install/QuartoProbeTest 16 pass
Unit/Install/UninstallCommandTest 17 pass
Unit/Install/VenvBuilderTest 15 pass
Unit/Project/AutoloadTest 16 pass
Unit/Project/ConfigTest 15 pass
Unit/VersionTest 4 pass
All 784 comparisons
Every comparison
Case Quantity Status
Engine/ChannelTest framing → it writes one JSON object per line pass
framing → it reads one line at a time, without the newline pass
framing → it reports end of input as null pass
framing → it keeps a newline inside a string from breaking the framing pass
framing → it leaves slashes and unicode readable on the wire pass
framing → it substitutes bytes that are not valid UTF-8 rather than failing pass
writing to a peer that has gone → it gives up quietly rather than throwing pass
writing to a peer that has gone → it stays quiet for every write after that pass
writing to a peer that has gone → it reads null once the peer has gone pass
writing to a peer that has gone → it is closed after close(), and writing then does nothing pass
a line longer than it will read → it gives up on an over-long line and resumes at the next one pass
a line longer than it will read → it treats a final line with no newline as the last thing said pass
connecting → it refuses clearly when there is nothing listening pass
connecting → it connects to a socket that is listening pass
the request shape task 6 writes → it reads the five request types pass
the request shape task 6 writes → it reads execute's fields, with the documented defaults pass
the request shape task 6 writes → it defaults the cursor to the end of the code, and clamps it pass
the request shape task 6 writes → it ignores a field of the wrong type rather than trusting it pass
the request shape task 6 writes → it refuses what is not a request, with a message fit for an evalue pass
the event shape task 6 reads → it puts the id and type first, then the type's own fields pass
the event shape task 6 reads → it builds each reply with the fields the contract names pass
the event shape task 6 reads → it always gives is_complete_reply an indent, even when empty pass
the event shape task 6 reads → it carries a null id for a complaint about the channel itself pass
the event shape task 6 reads → it keeps a traceback it was given rather than making one up pass
the event shape task 6 reads → it reports the running PHP version in kernel_info_reply pass
Engine/EngineTest the connection → it connects to the socket named in JUPHYTER_SOCKET pass
the connection → it keeps its own stdout and stderr clear of the protocol pass
the connection → it exits 0 when the transport closes the channel without asking pass
every request ends with one terminal event → it ends a cell with nothing to show in a single ok pass
every request ends with one terminal event → it ends a cell with a value in result then ok pass
every request ends with one terminal event → it ends a thrown cell in error, with no ok pass
every request ends with one terminal event → it answers each other request with its matching reply pass
every request ends with one terminal event → it tags every event with the id of the request it answers pass
a session across requests → it carries state from one cell to the next pass
a session across requests → it carries a declared function and an import across cells pass
a session across requests → it refuses a redeclaration, so one session guards the whole process pass
streaming → it sends each print as its own event, in order, before the terminal one pass
streaming → it sends what a cell printed before the error that followed it pass
streaming → it sends a warning on stderr rather than as an error pass
the execution count → it advances once per stored cell and matches what the front end shows pass
the execution count → it does not advance when store_history is false pass
the execution count → it reports the same count on result and ok pass
the execution count → it advances for a cell that failed, as a notebook does pass
the execution count → it labels a traceback with the number the front end shows pass
silent → it suppresses the result but not the terminal event pass
silent → it suppresses a display but not an error pass
silent → it does not suppress stream output, which a cell asked for explicitly pass
silent → it applies to one request only pass
the display wiring → it turns a cell value into a result with a text/plain bundle pass
the display wiring → it publishes nothing extra for a cell that ends in display() pass
the display wiring → it turns Juphyter\display() into a display event rather than stdout pass
the display wiring → it publishes several values in the order display() was given them pass
the display wiring → it gives a display event a metadata field, as the contract says pass
is_complete → it calls finished source complete pass
is_complete → it calls source that only wanted a semicolon complete pass
is_complete → it calls an unclosed brace incomplete, with an indent to continue at pass
is_complete → it indents one level further after a line that opened a brace pass
is_complete → it calls a syntax error invalid pass
is_complete → it does not touch the session, however often a front end asks pass
is_complete → it does not advance the execution count pass
kernel_info → it reports the PHP version actually running pass
kernel_info → it carries a banner naming the version too pass
completion → it completes a session variable after $ pass
completion → it completes a declared function by prefix pass
completion → it completes a declared class by prefix pass
completion → it completes a member after -> on a variable the session holds pass
completion → it completes a dynamic property, which a notebook value often has pass
completion → it completes a static member after :: pass
completion → it offers nothing for a member of a value it does not hold pass
completion → it offers nothing rather than guessing where there is no token pass
malformed input → it answers a line that is not JSON and keeps serving pass
malformed input → it answers JSON that is not an object pass
malformed input → it answers a request with no id pass
malformed input → it answers a request with no type, against its id pass
malformed input → it answers an unknown type against the id it was given pass
malformed input → it keeps serving after several bad lines in a row pass
malformed input → it does not hang on a line with no newline at the end pass
shutdown → it replies, then exits 0 pass
shutdown → it echoes the restart flag the transport sent pass
shutdown → it closes the channel, so there is nothing more to read pass
shutdown → it does not report the shutdown as a cell having ended the process pass
a cell that ends the process → it is reported as SystemExit pass
a cell that ends the process → it still delivers what the cell printed first pass
interrupts → it reports an interrupt and keeps the session usable pass
interrupts → it is not swallowed by the cell's own catch (Exception) pass
interrupts → it ignores a signal that arrives between cells pass
Engine/IdleTest it answers a request after sitting idle for longer than a read timeout pass
it exits when the transport closes the socket, timeout or no timeout pass
it waits out an expired read and still obeys end of input pass
Engine/ProjectTest the walk up → it gives a notebook its own project with no configuration at all pass
the walk up → it finds the project from a notebook in a subdirectory pass
the walk up → it serves perfectly well with no project at all pass
JUPHYTER_AUTOLOAD → it overrides the walk pass
JUPHYTER_AUTOLOAD → it is reported as an engine error when it names nothing, rather than hanging pass
juphyter.json → it names the autoloader, and beats the walk pass
juphyter.json → it loses to the environment pass
juphyter.json → it sets the memory limit the cells run under pass
juphyter.json → it adds to the include path without losing what was there pass
juphyter.json → it applies its settings even when it names no autoloader pass
juphyter.json → it is reported as an engine error when it is not valid JSON pass
the --autoload and --directory options → it takes an autoloader from the command line pass
the --autoload and --directory options → it takes the notebook directory from the command line pass
juphyter loading twice → it survives a project that carries its own copy of juphyter pass
Unit/Console/ApplicationTest discovery → it names a command from its class name pass
discovery → it finds the concrete commands in its directory, sorted by name pass
discovery → it scans its directory once, however many times it is asked pass
discovery → it leaves out abstract classes and files that are not PHP pass
discovery → it reports an empty directory as no commands pass
discovery → it treats a missing directory as empty rather than an error pass
discovery → it reads this package's own command directory without error pass
dispatch → it runs a registered command and returns its exit code pass
dispatch → it passes on the arguments after the subcommand name pass
dispatch → it dispatches a kebab-cased name pass
construction → it lists a command with a required constructor argument pass
construction → it dispatches a command with a required constructor argument through make() pass
construction → it does not construct a command to list it pass
construction → it reports a command it cannot build, rather than dying pass
construction → it still lists and dispatches the other commands when one cannot be built pass
construction → it keeps the unknown-command path working alongside such a command pass
usage → it lists the commands on stdout and exits 0 with no arguments pass
usage → it lists the commands for --help and -h too pass
usage → it says so plainly when there is no command to list pass
usage → it still rejects an unknown command when nothing is registered pass
usage → it prints usage to stderr and exits non-zero for an unknown command pass
usage → it does not run a command when the name is unknown pass
version → it reports the version on stdout and exits 0 for --version and -V pass
version → it answers even when no command can be listed pass
version → it treats a lowercase -v as an unknown command rather than the version flag pass
Unit/Console/OptionsTest parsing → it reads an option and its value as two arguments pass
parsing → it reads an option joined to its value by an equals sign pass
parsing → it reads both forms together, in any order pass
parsing → it reads nothing from nothing pass
parsing → it keeps a value that contains an equals sign pass
parsing → it keeps an empty value given with = pass
parsing → it lets a later option win over an earlier one pass
complaints → it refuses a stray argument, and shows the usage pass
complaints → it refuses an unknown option, and shows the usage pass
complaints → it refuses an option with no value pass
complaints → it refuses an option whose value is the next option pass
complaints → it includes the command's own usage in a complaint pass
help → it spots --help and -h anywhere in the arguments pass
help → it spots help even beside something malformed, so help still works pass
help → it is false when help was not asked for pass
Unit/Console/ReferenceTest it documents every option a command prints with data set "('install')" pass
it documents every option a command prints with data set "('uninstall')" pass
it documents every option a command prints with data set "('doctor')" pass
it documents every option a command prints with data set "('engine')" pass
it documents every command the application lists pass
Unit/Display/ChartFormatterTest matching → it matches by name, so it claims nothing without phiz installed pass
the bundle → it publishes the four representations in order when vl-convert is there pass
the bundle → it leaves out image/svg+xml when vl-convert is not there pass
the bundle → it leaves out image/svg+xml rather than failing when the conversion does pass
the bundle → it publishes the spec under the v5 MIME type, schema and all pass
the bundle → it takes text/html from embed() pass
the one-line summary → it names the class, the mark, the rows and the Vega-Lite version pass
the one-line summary → it joins the marks of a layered plot pass
the one-line summary → it says how a composition is arranged with data set "('hconcat', 'side by side')" pass
the one-line summary → it says how a composition is arranged with data set "('vconcat', 'stacked')" pass
the one-line summary → it says how a composition is arranged with data set "('concat', 'in a grid')" pass
the one-line summary → it finds the rows a composition carries in its first dataset pass
the one-line summary → it reads in the singular for one row pass
the one-line summary → it leaves out the rows when the data is behind a URL pass
the one-line summary → it names the class alone when the spec says nothing it can use pass
a real phiz chart → it matches a Plot and a Compose through their shared base pass
a real phiz chart → it publishes a Plot with the spec and the embed phiz produced pass
a real phiz chart → it describes a Compose by how it arranges its plots pass
a real phiz chart → it reaches a chart through the default registry pass
a real vl-convert binary → it publishes an SVG that vl-convert actually rendered pass
a real vl-convert binary → it publishes an SVG for a composition too pass
a real vl-convert binary → it finds the binary the way phiz does, and misses it when nothing points at one pass
Unit/Display/DisplayFunctionTest the exported function → it is loaded by the autoloader, not by an include pass
the exported function → it publishes one bundle for one value pass
the exported function → it publishes the whole bundle a formatter built, not only its text pass
the exported function → it publishes several values in the order given pass
the exported function → it formats with the current registry pass
with no publisher installed → it writes text/plain to standard output pass
with no publisher installed → it goes back to that after a publisher is removed pass
Unit/Display/DumperTest scalars → it renders null, booleans and integers pass
scalars → it keeps a float reading as a float pass
scalars → it names the floats that have no digits pass
scalars → it quotes a string so it cannot be read as a number pass
scalars → it escapes quotes, backslashes and newlines in a string pass
scalars → it clips a long string pass
arrays → it renders a list on one line pass
arrays → it renders keys for a map pass
arrays → it nests while it fits pass
arrays → it stops at the depth limit pass
arrays → it counts the entries past the item limit pass
arrays → it wraps a long list of scalars instead of giving each a line pass
arrays → it still gives a nested entry its own line pass
arrays → it expands one entry per line when the line would be too long pass
arrays → it keeps an inner entry on one line while that one fits pass
arrays → it never widens past the budget by indenting pass
objects → it names an enum case pass
objects → it names a closure without trying to describe it pass
objects → it renders a date as a date pass
objects → it lists the public properties of an object pass
objects → it says so when an object has no public properties pass
objects → it stops at the depth limit pass
everything else → it names a resource by its type pass
Unit/Display/FallbackFormattersTest scalars → it supports null and every scalar, and nothing else pass
scalars → it carries text/plain and nothing else pass
arrays → it leaves a flat list as plain text alone pass
arrays → it offers application/json for a nested array pass
arrays → it leaves out application/json when the array cannot be encoded pass
objects → it dumps the public properties of an object as text pass
objects → it offers application/json only when the class opted in pass
throwables → it prints the class, the message and where it came from pass
throwables → it leaves out the colon when there is no message pass
throwables → it supports every throwable, errors included pass
Unit/Display/MimeBundleTest construction → it starts empty pass
construction → it carries text/plain from plain() pass
construction → it answers null for a type it does not carry pass
immutability → it leaves the original alone when a type is added pass
immutability → it leaves the original alone when a type is removed pass
order → it keeps the types in insertion order pass
order → it keeps a type in place when it is set again pass
data → it carries a decoded structure, not only strings pass
data → it keeps metadata per type and only when given pass
data → it drops the metadata along with the type pass
Unit/Display/NoSiblingAtCompileTimeTest it names no package of the family at compile time with data set "dataset "src/Display/Formatter.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/ArrayFormatter.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/ChartFormatter.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/Dumper.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/HtmlFormatter.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/MimeBundleFormatter.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/ObjectFormatter.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/Reflect.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/ScalarFormatter.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/TableFormatter.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Formatters/ThrowableFormatter.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Html/TableRenderer.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/MimeBundle.php"" pass
it names no package of the family at compile time with data set "dataset "src/Display/Registry.php"" pass
it names no package of the family at compile time with data set "dataset "src/functions.php"" pass
it has the names it matches on as plain strings pass
it loads every class in the display layer with none of the family installed pass
Unit/Display/RegistryTest dispatch order → it ships the formatters in the documented order pass
dispatch order → it takes the first formatter that supports the value pass
dispatch order → it stops asking once one has claimed the value pass
dispatch order → it asks them in order until one claims the value pass
dispatch order → it does not merge the bundles of two formatters pass
composition → it puts prepended formatters first pass
composition → it puts appended formatters last pass
composition → it leaves the registry it was built from alone pass
text/plain → it is on every bundle the registry returns with data set "(null)" pass
text/plain → it is on every bundle the registry returns with data set "(false)" pass
text/plain → it is on every bundle the registry returns with data set "(0)" pass
text/plain → it is on every bundle the registry returns with data set "(1.5)" pass
text/plain → it is on every bundle the registry returns with data set "('')" pass
text/plain → it is on every bundle the registry returns with data set "([])" pass
text/plain → it is on every bundle the registry returns with data set "([1, 2, 3])" pass
text/plain → it is on every bundle the registry returns with data set "([['c']])" pass
text/plain → it is on every bundle the registry returns with data set "(Closure Object ()) #1" pass
text/plain → it is on every bundle the registry returns with data set "(Closure Object ()) #2" pass
text/plain → it is on every bundle the registry returns with data set "(Closure Object ()) #3" pass
text/plain → it is on every bundle the registry returns with data set "(Closure Object ()) #4" pass
text/plain → it is filled in when a formatter left it out pass
text/plain → it is the whole bundle for a value nothing claimed pass
the current registry → it defaults to the shipped formatters pass
the current registry → it can be replaced, and restored with null pass
Unit/Display/TableFormatterTest matching → it matches by name, so it claims nothing without phibble installed pass
the bundle → it carries text/html first, then text/plain pass
the bundle → it takes text/plain from the collected frame itself pass
the bundle → it renders the HTML when the table has none of its own pass
the bundle → it prefers a toHtml() the table brought itself pass
the bundle → it collects a lazy table once, for both representations pass
the bundle → it uses the renderer it was given pass
a real phibble table → it matches a DataFrame pass
a real phibble table → it prints a DataFrame exactly as phibble prints it pass
a real phibble table → it renders a DataFrame as HTML, to its snapshot pass
a real phibble table → it matches a SqlTable, and prints it as phibble does pass
a real phibble table → it would match a PolarsTable, which implements the same contract pass
a real phibble table → it matches a PolarsTable instance when php_polars is loaded pass
Unit/Display/TableRendererTest snapshots → it renders a small frame pass
snapshots → it renders a frame with rows and columns held back pass
snapshots → it renders a grouped frame pass
snapshots → it renders a frame with no rows pass
the header → it states the dimensions as phibble does pass
the header → it separates the thousands in a big dimension pass
the header → it gives every column its type abbreviation pass
the header → it names the group columns, and says rowwise when it is pass
the header → it leaves the grouping line out when the frame is ungrouped pass
the footer → it counts the rows it held back pass
the footer → it names the columns it held back, with their types pass
the footer → it reads in the singular for one row and one column pass
the footer → it is left out when the whole frame is shown pass
cells → it marks a null as NA pass
cells → it prints booleans as phibble prints them pass
cells → it prints a date without the time pass
cells → it prints a datetime with the time pass
cells → it escapes markup in a string pass
cells → it escapes a newline rather than breaking the row pass
cells → it gives a list column its length pass
cells → it clips a long string pass
cells → it names the floats that have no digits pass
cells → it right-aligns the numeric columns and leaves the rest alone pass
cells → it fills in a cell the row is missing pass
a table from somewhere else → it renders a type it cannot abbreviate pass
a table from somewhere else → it holds rows back itself when the table offers no head() pass
Unit/Display/UserTypesTest toMimeBundle() → it takes precedence over every built-in formatter pass
toMimeBundle() → it is first in the default registry, ahead of toHtml() pass
toMimeBundle() → it fills in text/plain from __toString() when the bundle left it out pass
toMimeBundle() → it accepts a MimeBundle as well as a map pass
toMimeBundle() → it falls back to the dump when the return is not a MIME map pass
toHtml() → it becomes the text/html of the bundle pass
toHtml() → it takes text/plain from __toString() when the class has one pass
toHtml() → it takes text/plain from the dump when the class has no text form pass
what does not count as a hook → it ignores a static toMimeBundle() and a toHtml() that needs an argument pass
what does not count as a hook → it asks for a public, static-free, argument-free method pass
matching by name → it never reports a class name string as an instance pass
matching by name → it answers false for a class no installed package declares pass
Unit/Engine/CleanerTest parse errors → it refuses source that does not parse, with the parser's own message pass
parse errors → it reports the line in the user's cell, not in the prelude pass
parse errors → it leaves the session untouched when it refuses a cell pass
parse errors → it does not record a declaration from a cell it refuses pass
the forgiving semicolon → it accepts a bare trailing expression and captures it pass
the forgiving semicolon → it accepts a bare variable, which is how a notebook asks what something is pass
the forgiving semicolon → it accepts a cell ending in a // comment, which the bare semicolon could not pass
the forgiving semicolon → it accepts a cell ending in a # comment, which is what Quarto writes pass
the forgiving semicolon → it still evals a cell that ended in a comment pass
the forgiving semicolon → it says so when it did not have to append anything pass
the forgiving semicolon → it still refuses an unclosed brace, with the original message pass
the forgiving semicolon → it reports the original error, not the retry's, when the retry fails differently pass
the forgiving semicolon → it keeps the original error's line when the retry fails pass
the forgiving semicolon → it does not retry an error that is not source running out pass
the forgiving semicolon → it leaves the line mapping untouched, because it only ever appends pass
the forgiving semicolon → it produces source that really evals, semicolon and all pass
incomplete versus invalid → it calls an unclosed brace incomplete, not invalid pass
incomplete versus invalid → it calls an unclosed call incomplete pass
incomplete versus invalid → it calls an unclosed string incomplete pass
incomplete versus invalid → it calls a genuine syntax error invalid, not incomplete pass
incomplete versus invalid → it calls a stray closing brace invalid pass
incomplete versus invalid → it does not call a refused namespace incomplete, because it parsed pass
incomplete versus invalid → it does not call a redeclaration incomplete pass
incomplete versus invalid → it does not call a refused declare incomplete pass
incomplete versus invalid → it does not call an alias clash incomplete pass
incomplete versus invalid → it gives the transport all three answers without it reading a parser message pass
the prelude → it prepends declare(strict_types=1) to every cell pass
the prelude → it is one line when nothing is imported pass
the prelude → it enforces strict types, which is the point of prepending it pass
the prelude → it re-emits every accumulated import ahead of a later cell pass
the cell's own declare → it strips declare(strict_types=1) the user wrote, which PHP would reject there pass
the cell's own declare → it does not let a stripped declare shift the lines below it pass
the cell's own declare → it survives eval with the user's own declare stripped pass
the cell's own declare → it refuses declare(strict_types=0), which it cannot honour pass
the cell's own declare → it refuses declare(encoding=...), which can no longer be first pass
the cell's own declare → it refuses block-mode strict_types pass
the cell's own declare → it refuses strict_types combined with another directive, rather than dropping it pass
the cell's own declare → it refuses the combination whichever order it is written in pass
the cell's own declare → it names every directive it would have discarded pass
the cell's own declare → it leaves declare(ticks=1) where the user put it pass
imports → it lifts the cell's use into the session so later cells see it pass
imports → it removes the use from the body, because the prelude now carries it pass
imports → it emits the cell's own import exactly once, which PHP requires pass
imports → it handles use function and use const pass
imports → it expands a grouped use into one statement per name pass
imports → it reads the per-name type out of a mixed grouped use pass
imports → it keeps a use that follows code in the same cell pass
imports → it refuses one cell binding the same alias to two names pass
imports → it allows one cell repeating the same import, which is harmless pass
imports → it lets a later cell rebind an alias, with the new one winning pass
imports → it does not fatal when a cell rebinds an alias an earlier cell bound pass
namespace → it refuses a namespace declaration, naming the limitation pass
namespace → it refuses a braced namespace too pass
redeclaration → it reports every kind of top-level declaration on the result pass
redeclaration → it reports nothing for a cell that declares nothing pass
redeclaration → it does not put the names into the session, which is the executor's job pass
redeclaration → it refuses a class the session already holds, with the name in the message pass
redeclaration → it refuses a function the session already holds pass
redeclaration → it refuses an interface that collides with a class, because PHP shares the namespace pass
redeclaration → it refuses an enum that collides with a trait, for the same reason pass
redeclaration → it matches a held name case-insensitively, as PHP does pass
redeclaration → it allows a function and a class of the same name, which PHP allows pass
redeclaration → it refuses a name the one cell declares twice pass
redeclaration → it refuses a function the one cell declares twice pass
redeclaration → it reports the line the colliding declaration is on pass
redeclaration → it leaves a conditional declaration alone, because PHP does not hoist it pass
redeclaration → it accepts the same conditional declaration twice pass
redeclaration → it does not treat a method of a class as a declaration pass
redeclaration → it does not treat an anonymous class as a declaration pass
committing declarations → it reserves nothing for a cell that was cleaned but never run pass
committing declarations → it does not reserve a name the cell failed to declare, so the typo can be fixed pass
committing declarations → it does the same for a class whose interface does not exist pass
committing declarations → it reserves a name the cell declared before it threw, because PHP hoists it pass
committing declarations → it reserves a function only once it exists pass
committing declarations → it lets a subclass run again once the base class it needed arrives pass
committing declarations → it commits nothing for a cell that declares nothing pass
capturing the cell's value → it assigns a trailing expression into the reserved variable pass
capturing the cell's value → it captures a call, which is the common notebook case pass
capturing the cell's value → it captures only the last statement pass
capturing the cell's value → it does not capture an assignment pass
capturing the cell's value → it does not capture a compound assignment pass
capturing the cell's value → it does not capture a reference assignment pass
capturing the cell's value → it does not capture an increment or a decrement pass
capturing the cell's value → it does not capture echo, which is a statement rather than an expression pass
capturing the cell's value → it does not capture print pass
capturing the cell's value → it does not capture a declaration pass
capturing the cell's value → it does not capture a control structure pass
capturing the cell's value → it does not capture a return pass
capturing the cell's value → it captures a value that eval really does leave in the variable pass
capturing the cell's value → it does not shift any line when it inserts the capture pass
cells with nothing in them → it accepts an empty cell pass
cells with nothing in them → it accepts a cell of only whitespace pass
cells with nothing in them → it accepts a cell of only a comment, and keeps it pass
cells with nothing in them → it accepts a Quarto cell option, which is a PHP comment pass
the line mapping → it maps a source line back to the cell line it came from pass
the line mapping → it keeps the mapping exact for every line of a cell, however it was edited pass
the line mapping → it holds for a real traceback line that eval reports pass
a ten-cell round trip → it keeps the prelude line count correct as the import set grows pass
a ten-cell round trip → it produces source that evals cleanly at every step of such a session pass
Unit/Engine/ExecutorTest terminal events → it ends a cell with nothing to show in a single ok pass
terminal events → it emits the result immediately before ok, carrying the execution count pass
terminal events → it emits no result for a cell the cleaner found no value in pass
terminal events → it ends a thrown cell in a single error and no ok pass
terminal events → it reports a refused cell as an error without running anything pass
terminal events → it reports a parse error with the cleaner's ename and the cell's line pass
terminal events → it reports a refusal that has no line without inventing one pass
variables between cells → it keeps scalars, arrays and objects pass
variables between cells → it keeps the same object, not a copy of it pass
variables between cells → it keeps a resource open across cells pass
variables between cells → it keeps functions and classes a cell declared pass
variables between cells → it removes a variable a cell unset, rather than merging it back pass
variables between cells → it keeps the variables a cell bound before it threw pass
variables between cells → it never leaks the reserved result variable into the session pass
variables between cells → it never leaks any reserved variable into the session pass
variables between cells → it does not carry a reference across cells, which no PHP REPL does pass
variables between cells → it starts a cell with the session already in scope pass
output → it turns what a cell prints into a stdout stream event pass
output → it emits each print separately and in order pass
output → it emits output as it is produced, not when the cell ends pass
output → it delivers output before the error of a cell that printed and then threw pass
output → it does not let the cell's output reach the real stdout pass
output → it closes a buffer the cell left open, without taking any outer one pass
output → it survives a cell that closes more buffers than it opened pass
diagnostics → it turns a warning into a stderr stream event, not a result pass
diagnostics → it turns a deprecation into a stderr stream event pass
diagnostics → it turns a user notice into a stderr stream event pass
diagnostics → it drops a diagnostic the cell suppressed with @ pass
diagnostics → it still ends a warning-producing cell with ok pass
diagnostics → it names the cell line a warning came from pass
strict types → it enforces strict types, so a weak argument is a TypeError pass
strict types → it still accepts a correctly typed argument pass
committing declarations → it holds a class a cell declared before it threw, and refuses the cell again pass
committing declarations → it does not hold a class whose parent was missing, and runs the corrected cell pass
committing declarations → it commits after a cell that was interrupted or failed for any reason pass
display → it publishes a value mid-cell as a display event pass
display → it publishes an already-formatted bundle without formatting it again pass
display → it defaults a published bundle's metadata to empty pass
display → it routes publish() through publishBundle, so one place builds the event pass
display → it takes metadata for a published value pass
display → it uses an injected formatter for a result instead of the fallback pass
display → it uses an injected formatter for a published value too pass
display → it describes the common value kinds in its fallback pass
a value of null → it publishes no result, and still ends in ok pass
a value of null → it publishes nothing for a void call as the last statement pass
a value of null → it leaves var_dump with its output and no result pass
a value of null → it still advances the execution count pass
a value of null → it publishes every other falsy value, which are values a cell meant pass
the session object → it uses a session it was given, so the transport can share one pass
the session object → it carries accumulated imports into a later cell pass
in a child process → it runs cells and emits the same events there pass
in a child process → it reports an exhausted memory limit from the shutdown handler pass
in a child process → it reports an interrupt and leaves the session usable pass
in a child process → it keeps the variables an interrupted cell had already bound pass
in a child process → it is not swallowed by a cell's own catch (Exception) pass
in a child process → it ignores a signal that arrives between cells rather than dying pass
a cell that ends the process → it reports a bare exit as a terminal error pass
a cell that ends the process → it reports exit(0) the same way pass
a cell that ends the process → it reports exit with a non-zero code, and the code still reaches the parent pass
a cell that ends the process → it delivers what die() printed before the terminal error pass
a cell that ends the process → it stops the cells after it, since the process is gone pass
a cell that ends the process → it says nothing extra on an ordinary shutdown pass
a cell that ends the process → it says nothing when the shutdown is one the engine asked for pass
a cell that ends the process → it still reports an unmarked exit, so the mark is what makes the difference pass
a cell that ends the process → it still delivers what a cell printed before an expected shutdown pass
a cell that ends the process → it still reports a fatal even when a shutdown was expected pass
a cell that ends the process → it reports a fatal from a cell that had already printed something pass
a cell that ends the process → it reports a fatal after a cell has printed megabytes pass
a cell that ends the process → it reports a fatal whose own allocation was a small one pass
a cell that ends the process → it still reports a fatal as a fatal rather than as an exit pass
Unit/Engine/SessionTest imports → it starts with nothing imported pass
imports → it renders a class import, and leaves out a redundant alias pass
imports → it renders function and constant imports with their keyword pass
imports → it renders an unnamespaced import pass
imports → it keeps the statements sorted, so one session always prints the same pass
imports → it replaces an earlier binding of the same alias pass
imports → it keeps the three use types apart, as PHP does pass
imports → it treats a class alias case-insensitively, as PHP does pass
imports → it treats a function alias case-insensitively, as PHP does pass
imports → it treats a constant alias case-sensitively, as PHP does pass
imports → it reports nothing for an alias it does not hold pass
declared names → it starts with nothing declared pass
declared names → it remembers a class-like name and keeps the spelling the cell used pass
declared names → it matches a class-like name case-insensitively, as PHP does pass
declared names → it matches a function name case-insensitively, as PHP does pass
declared names → it keeps class-like names and functions apart, because PHP does pass
declared names → it holds one entry for a name declared twice pass
committing declarations → it records a name that exists in the runtime pass
committing declarations → it ignores a name that does not exist, however valid the cell was pass
committing declarations → it records an interface, a trait and an enum, not only a class pass
committing declarations → it records a function that exists pass
committing declarations → it ignores a function that does not exist pass
committing declarations → it does not count a name only the autoloader could find pass
committing declarations → it commits nothing for a cell that declares nothing pass
Unit/Engine/TracebackTest a throw from cell code → it reports the cell and the line the user wrote pass
a throw from cell code → it subtracts the prelude, however long it has grown pass
a throw from cell code → it reports the class of the thrown value as the ename line pass
a throw from cell code → it reports an Error as readily as an Exception pass
a throw from cell code → it stops at the executor, leaving juphyter's own frames out pass
a throw from a function an earlier cell declared → it maps the throw to the cell that declared the function pass
a throw from a function an earlier cell declared → it uses the declaring cell's prelude, not the running cell's pass
a throw from a function an earlier cell declared → it maps a method of a class an earlier cell declared pass
a throw from a function an earlier cell declared → it maps a static method too pass
a throw from a function an earlier cell declared → it maps a chain through two earlier cells pass
a throw from inside vendor code → it leaves a vendor frame as its own file and line pass
a throw from inside vendor code → it rewrites the cell frame while leaving the vendor frames alone pass
a throw from inside vendor code → it names the function a vendor frame was called from pass
a throw from inside vendor code → it does not report an internal function's location twice pass
a frame no cell claims → it says what a closure is without claiming to know where pass
a frame no cell claims → it never shows the closure's raw name, whatever this PHP calls it pass
a frame no cell claims → it treats a closure declared and called in one cell the same way pass
a frame no cell claims → it treats an arrow function the same way pass
a frame no cell claims → it still places the cell frame that called the closure pass
an interrupt → it reports KeyboardInterrupt rather than the exception class pass
an interrupt → it does not show the kernel's own signal handler or its path pass
a refused cell → it reads as the refusal and the line the user wrote pass
a refused cell → it omits the location when the refusal has no line pass
describing one location → it returns null for a file that is not evaluated code pass
describing one location → it recognises evaluated code by its file name pass
describing one location → it maps a line through the running cell when nothing else claims it pass
describing one location → it is what a warning's location comes from pass
Unit/Install/DoctorCommandTest a healthy machine → it reports every check and says both front ends are ready pass
a healthy machine → it names every usable kernel in the verdict pass
a healthy machine → it changes nothing it looked at pass
Quarto → it says it is not installed rather than not ready pass
Quarto → it fails when the interpreter Quarto will run has no Jupyter, and gives the PATH entry pass
Quarto → it takes the PATH entry from a working kernel when no interpreter is usable now pass
a Python that cannot host the kernel → it fails and prints the command that fixes it pass
a Python that cannot host the kernel → it fails an ipykernel older than the kernel needs pass
kernels whose recorded paths have moved → it names a PHP that no longer runs pass
kernels whose recorded paths have moved → it names an engine a deleted project took with it pass
kernels whose recorded paths have moved → it names a Python wrapper that is gone pass
kernels whose recorded paths have moved → it names a Python that lost its ipykernel pass
what it leaves alone → it ignores a kernel juphyter did not write pass
what it leaves alone → it says so when nothing is installed, and what to run pass
what it leaves alone → it says to install a Python first when there is not one either pass
the command surface → it prints its own help for --help and -h pass
the command surface → it documents --prefix and the exit code pass
the command surface → it rejects an unknown option pass
the command surface → it is dispatched as "doctor" and describes itself pass
it treats a default Python that cannot host a kernel as advisory once kernels work pass
Unit/Install/InstallCommandTest writing the kernelspec → it writes one under the Jupyter data directory pass
writing the kernelspec → it writes one under a prefix, as jupyter kernelspec install does pass
writing the kernelspec → it takes an option as --name=value too pass
writing the kernelspec → it reports where it went pass
writing the kernelspec → it creates the kernels directory when it is not there yet pass
writing the kernelspec → it adds JUPHYTER_AUTOLOAD when --autoload is given pass
writing the kernelspec → it lowercases the kernel name pass
writing the kernelspec → it refuses a name it cannot use, before writing anything pass
several PHP versions side by side → it keeps two kernels apart by --name and --display-name pass
several PHP versions side by side → it replaces its own kernelspec when the same name is installed again pass
several PHP versions side by side → it leaves a kernelspec it did not write alone pass
the Python interpreter → it names the interpreter the probe chose pass
the Python interpreter → it writes nothing and prints the pip command when ipykernel is missing pass
the Python interpreter → it writes nothing when ipykernel is too old for the wrapper pass
the Python interpreter → it writes nothing when the interpreter does not run pass
the PHP binary → it defaults to the PHP running the command, without starting a process pass
the PHP binary → it records the default PHP under the PATH symlink that reaches it, as Homebrew needs pass
the PHP binary → it keeps the binary when no PATH entry reaches it pass
the PHP binary → it looks only for the same name, so php8.3 is never swapped for php pass
the PHP binary → it validates --php by running it, and takes the path it reports pass
the PHP binary → it keeps an absolute --php exactly as it was given pass
the PHP binary → it resolves a bare name through the binary it reports pass
the PHP binary → it resolves a relative path through the binary it reports pass
the PHP binary → it probes the path it was given, and not the one that comes back pass
the PHP binary → it writes nothing when --php does not run pass
the PHP binary → it writes nothing when --php runs but reports no version pass
running from a PHAR → it names the archive as the engine and copies the wrapper out of it pass
running from a PHAR → it refuses an archive with no wrapper module in it pass
the missing Python wrapper → it fails and writes nothing when the package has no wrapper module pass
the missing Python wrapper → it fails when the module directory is there but the module is not pass
the missing Python wrapper → it asks nothing of Python when the wrapper is missing pass
the missing Python wrapper → it installs when the module is there pass
the command surface → it is dispatched as "install" and describes itself without being built pass
the command surface → it prints its own help for --help and -h pass
the command surface → it rejects an unknown option and shows the usage pass
the command surface → it rejects an argument that is not an option pass
the command surface → it rejects an option with no value pass
the command surface → it is built by make() without arguments, the way the dispatcher builds it pass
the command surface → it resolves its package root to this checkout outside a PHAR pass
the command surface → it writes a kernelspec that uninstall recognizes as juphyter's pass
the stop button → it says nothing when the target PHP can handle signals pass
the stop button → it warns and names the binary when it cannot, and still installs pass
the stop button → it names the path the user gave in the warning, not the one PHP reports pass
the stop button → it still reports the install on stdout alongside the warning pass
the stop button → it asks the target PHP the same question Interrupt::available() asks pass
the stop button → it says nothing when an older probe answers with only two lines pass
the stop button → it checks the running PHP when no --php is given pass
the interpreter Quarto will use → it says nothing about Quarto when quarto is not on PATH pass
the interpreter Quarto will use → it names the interpreter and its jupyter_client when it has one pass
the interpreter Quarto will use → it reports no Jupyter, warns, and installs anyway pass
the interpreter Quarto will use → it leaves the kernelspec naming the recorded interpreter, not Quarto's pass
the interpreter Quarto will use → it takes QUARTO_PYTHON over the python3 on PATH pass
the interpreter Quarto will use → it reports a QUARTO_PYTHON that does not run, and still installs pass
the interpreter Quarto will use → it reports that there is no python3 on PATH for Quarto to use pass
the interpreter Quarto will use → it suggests no PATH entry when the recorded interpreter has no Jupyter either pass
the interpreter Quarto will use → it asks the resolved interpreter for jupyter_client and nothing else pass
the Quarto check against a real interpreter → it warns and names the Jupyter-less python3 that is first on PATH pass
building a Python when none can host the kernel → it offers to build one and installs into it when the answer is yes pass
building a Python when none can host the kernel → it does not ask when --create-venv names a directory pass
building a Python when none can host the kernel → it says what it is building, because installing it takes a minute pass
building a Python when none can host the kernel → it declines without a terminal and names the option that would do it pass
building a Python when none can host the kernel → it does not offer to build when --python named an interpreter pass
building a Python when none can host the kernel → it has no default directory to offer when HOME is unset pass
building a Python when none can host the kernel → it lists --create-venv in its help pass
shell startup files → it writes to none, and offers no option that would pass
shell startup files → it rejects --path-file, which it no longer has pass
Unit/Install/JupyterPathsTest the data directory → it uses JUPYTER_DATA_DIR when it is set pass
the data directory → it ignores an empty JUPYTER_DATA_DIR pass
the data directory → it drops a trailing separator pass
the data directory → it puts it under ~/Library/Jupyter on macOS pass
the data directory → it puts it under XDG_DATA_HOME on Linux pass
the data directory → it falls back to ~/.local/share on Linux without XDG_DATA_HOME pass
the data directory → it treats BSD like Linux pass
the data directory → it follows JUPYTER_PLATFORM_DIRS to the platformdirs location pass
the data directory → it reads the words jupyter_core reads as false pass
the data directory → it refuses Windows, which the kernel cannot run on pass
the data directory → it says what to do when HOME is not set pass
the kernels directory → it sits inside the data directory pass
the kernels directory → it moves under a prefix when one is given pass
the kernels directory → it ignores an empty prefix pass
the kernels directory → it does not need HOME or a platform when a prefix is given pass
the kernels directory → it names one kernelspec after the kernel pass
the kernels directory → it collapses a doubled separator from a prefix with a trailing slash pass
it reads the running process in fromEnvironment pass
Unit/Install/KernelSpecTest the kernel name → it lowercases a name and trims it pass
the kernel name → it allows dots, dashes, and underscores pass
the kernel name → it rejects a name Jupyter cannot select with data set "('')" pass
the kernel name → it rejects a name Jupyter cannot select with data set "(' ')" pass
the kernel name → it rejects a name Jupyter cannot select with data set "('php 85')" pass
the kernel name → it rejects a name Jupyter cannot select with data set "('php/85')" pass
the kernel name → it rejects a name Jupyter cannot select with data set "('../escape')" pass
the kernel name → it rejects a name Jupyter cannot select with data set "('.hidden')" pass
the kernel name → it rejects a name Jupyter cannot select with data set "('-leading-dash')" pass
the kernel name → it rejects a name Jupyter cannot select with data set "('php:85')" pass
the kernel name → it rejects a name Jupyter cannot select with data set "('php*')" pass
the kernel name → it keeps a name out of the parent directory pass
the document → it holds the keys Jupyter reads, in the plan's order pass
the document → it leaves {connection_file} for Jupyter to substitute pass
the document → it interrupts by signal, because the wrapper forwards SIGINT pass
the document → it adds JUPHYTER_AUTOLOAD only when an autoloader is given pass
the document → it reports its own name pass
the JSON → it round-trips through json_decode pass
the JSON → it is indented, unescaped, and ends with a newline pass
recognizing juphyter's own kernelspec → it recognizes what it wrote pass
recognizing juphyter's own kernelspec → it does not claim a kernelspec from another kernel with data set "dataset "a python kernel"" pass
recognizing juphyter's own kernelspec → it does not claim a kernelspec from another kernel with data set "dataset "another PHP kernel"" pass
recognizing juphyter's own kernelspec → it does not claim a kernelspec from another kernel with data set "dataset "a PHP kernel with an empty engine"" pass
recognizing juphyter's own kernelspec → it does not claim a kernelspec from another kernel with data set "dataset "a PHP kernel whose env is not a map"" pass
recognizing juphyter's own kernelspec → it does not claim a kernelspec from another kernel with data set "dataset "nothing at all"" pass
recognizing juphyter's own kernelspec → it does not claim a kernelspec from another kernel with data set "dataset "a string"" pass
recognizing juphyter's own kernelspec → it does not claim a kernelspec from another kernel with data set "dataset "an empty document"" pass
Unit/Install/PharTest the build → it produces a runnable archive pass
the build → it carries the production dependencies and not the dev ones pass
the build → it carries the Python wrapper, which a PHAR install copies out of it pass
the build → it leaves compiled Python bytecode out, however the checkout looks pass
the build → it drops the shebang of bin/juphyter, which would otherwise be printed pass
dispatching from the archive → it lists the commands it holds, because scandir() reads phar:// paths pass
dispatching from the archive → it lists every command the checkout lists pass
dispatching from the archive → it rejects an unknown command with usage and a non-zero code pass
dispatching from the archive → it dispatches a command it holds pass
installing from the archive → it writes a kernelspec that names the archive as the engine pass
installing from the archive → it copies the Python wrapper out of the archive pass
installing from the archive → it copies the real wrapper out, so the installed kernel can start pass
installing from the archive → it prints the pip command when a named interpreter has no ipykernel pass
installing from the archive → it builds an environment rather than touching an interpreter it was not given pass
installing from the archive → it uninstalls what it installed pass
Unit/Install/PythonProbeTest choosing an interpreter → it asks the interpreter --python names for its own path pass
choosing an interpreter → it reads the shebang of the jupyter on PATH pass
choosing an interpreter → it follows a /usr/bin/env shebang back to PATH pass
choosing an interpreter → it skips env options and assignments in a shebang pass
choosing an interpreter → it reads a quoted shebang path, which pip writes when the path holds a space pass
choosing an interpreter → it falls back to python3 when the shebang names something else pass
choosing an interpreter → it falls back to python3 when the shebang points at a missing interpreter pass
choosing an interpreter → it falls back to python when there is no python3 pass
choosing an interpreter → it skips a jupyter that is not executable pass
choosing an interpreter → it says what is missing when PATH holds no jupyter and no python pass
choosing an interpreter → it reports an interpreter that does not run, with its own message pass
choosing an interpreter → it reports an interpreter that exits cleanly and says nothing pass
requiring ipykernel → it returns the version it finds pass
requiring ipykernel → it asks the interpreter to import it pass
requiring ipykernel → it reports no version when the import fails pass
requiring ipykernel → it prints the exact install command when ipykernel is missing pass
requiring ipykernel → it refuses an ipykernel below the floor the wrapper needs pass
requiring ipykernel → it accepts the floor itself and anything above it pass
requiring ipykernel → it names the floor in one place pass
the default runner → it runs a process and returns its code and both streams pass
the default runner → it reports a path that is not there rather than throwing pass
the default runner → it reports an empty command pass
the default runner → it passes arguments without a shell, so nothing needs quoting pass
Unit/Install/QuartoProbeTest whether Quarto is installed → it finds quarto on PATH pass
whether Quarto is installed → it reports none when PATH has no quarto pass
whether Quarto is installed → it ignores a quarto that is not executable pass
resolving the interpreter → it takes the first python3 on PATH pass
resolving the interpreter → it takes QUARTO_PYTHON over the python3 on PATH pass
resolving the interpreter → it ignores an empty QUARTO_PYTHON pass
resolving the interpreter → it resolves the candidate to its own sys.executable pass
resolving the interpreter → it has nothing to resolve when PATH holds no python3 pass
resolving the interpreter → it does not fall back to python pass
a candidate that cannot be asked anything → it reports a QUARTO_PYTHON that is not there pass
a candidate that cannot be asked anything → it reports an exit code when the interpreter said nothing pass
a candidate that cannot be asked anything → it reports an interpreter that ran and printed no path pass
the jupyter_client check → it reports the version when it imports pass
the jupyter_client check → it reports none when it does not import pass
the jupyter_client check → it asks the resolved interpreter, and asks only about jupyter_client pass
the jupyter_client check → it can be asked of any interpreter pass
Unit/Install/UninstallCommandTest removing a kernelspec → it removes one juphyter wrote, under a prefix pass
removing a kernelspec → it removes one under the Jupyter data directory pass
removing a kernelspec → it removes the copy of the Python wrapper a PHAR install left inside it pass
removing a kernelspec → it removes only the kernel named pass
removing a kernelspec → it lowercases the name it is given pass
removing a kernelspec → it unlinks a symlink inside the kernelspec rather than following it pass
refusing to remove → it leaves a kernelspec juphyter did not write pass
refusing to remove → it leaves a Python kernelspec that happens to share the name pass
refusing to remove → it leaves a kernel.json it cannot parse pass
refusing to remove → it says there is nothing there when the kernel is not installed pass
refusing to remove → it says there is nothing there when the directory holds no kernel.json pass
refusing to remove → it refuses a name it cannot use pass
the command surface → it is dispatched as "uninstall" and describes itself without being built pass
the command surface → it prints its own help for --help and -h pass
the command surface → it rejects an unknown option, a stray argument, and a missing value pass
the command surface → it does not take install's options pass
the command surface → it is built by make() without arguments, the way the dispatcher builds it pass
Unit/Install/VenvBuilderTest building an environment → it creates one and installs the packages into its own interpreter pass
building an environment → it adopts an environment that already runs rather than rebuilding it pass
building an environment → it installs exactly the documented packages pass
building an environment → it drops a trailing slash from the directory it was given pass
refusing to build → it refuses a directory that exists and holds something pass
refusing to build → it builds into an empty directory that is already there pass
refusing to build → it refuses an empty directory name pass
refusing to build → it says so when PATH holds no Python to build with pass
reporting a failure → it reports why venv failed pass
reporting a failure → it reports a venv that claimed success and left nothing that runs pass
reporting a failure → it reports why pip failed, keeping the last lines of it pass
reporting a failure → it falls back to the exit code when a failure said nothing pass
the default directory → it is under HOME pass
the default directory → it collapses a trailing slash on HOME pass
the default directory → it is null when HOME is unset, so the caller asks instead of guessing pass
Unit/Project/AutoloadTest searching upwards → it finds an autoloader beside the notebook pass
searching upwards → it walks up until it finds one pass
searching upwards → it takes the nearest one, because a package inside a monorepo means the package pass
searching upwards → it finds nothing when there is nothing, which is not an error pass
searching upwards → it ignores a vendor directory with no autoloader in it pass
searching upwards → it does not fall over on a directory that is not there pass
precedence → it prefers the environment over everything pass
precedence → it prefers the config over the search pass
precedence → it falls back to the search when nothing names one pass
precedence → it reports finding nothing, rather than failing pass
precedence → it treats an empty environment variable as unset pass
an autoloader that was named but is not there → it refuses a missing path from the environment, naming the variable pass
an autoloader that was named but is not there → it refuses a missing path from the config, naming the file pass
an autoloader that was named but is not there → it says where it looked pass
loading → it requires the file it found pass
loading → it does nothing when it found nothing pass
Unit/Project/ConfigTest finding the file → it reads a juphyter.json beside the notebook pass
finding the file → it walks up, so one file at the top of a project serves its subdirectories pass
finding the file → it takes the nearest one pass
finding the file → it finds nothing when there is none pass
finding the file → it does not fall over on a directory that is not there pass
reading the file → it reads all three settings pass
reading the file → it leaves out what the file does not say pass
reading the file → it ignores a setting of the wrong type or an empty one pass
reading the file → it resolves a relative autoload path against the file, not the working directory pass
reading the file → it leaves an absolute autoload path alone pass
reading the file → it refuses invalid JSON, rather than ignoring a file the user wrote on purpose pass
reading the file → it refuses a file that is not a JSON object pass
applying the settings → it sets the memory limit pass
applying the settings → it prepends the include path rather than replacing it pass
applying the settings → it changes nothing it was not told to change pass
Unit/VersionTest the reported version → it reads this installation out of the Composer record pass
the reported version → it identifies a branch install by its commit pass
the reported version → it names the tool and the PHP running it, on one line pass
the reported version → it leaves off the archive path when no archive is running pass

Limitations

Exclusions

  • The case for syntax newer than the running PHP applies below PHP 8.5; the run uses PHP 8.5.

Reproduction

From the repository root
composer install
composer require --dev --prefer-source "phpstats/phibble:^0.5" "phpstats/phplyr:^0.4" "phpstats/phiz:^0.5"
php -d phar.readonly=0 -d extension=<path to php_polars> vendor/bin/pest
Raw record
site/verifications/family-compatibility.json
Full results
.github/workflows/family.yml