/**
  * build an exception message and data, including details of
  * - who is throwing the exception
  *
  * @param  string $message
  *         the message for your exception
  * @param  array $backtrace
  *         the output of debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)
  * @param  array $callerFilter
  *         list of classes to ignore in the backtrace
  * @return array
  *         - [0] is the message
  *         - [1] is the message data
  */
 public static function from($message, array $backtrace, array $callerFilter = [])
 {
     // who called us?
     $caller = FilterCodeCaller::from($backtrace, $callerFilter);
     // put it all together
     $exceptionData = ["thrownBy" => $caller, "thrownByName" => $caller->getCaller()];
     $msg = "%thrownByName\$s: {$message}";
     return [$msg, $exceptionData];
 }
 /**
  * @covers ::from
  */
 public function testReturnsFirstStackFrameWhenEverythingElseFilteredOut()
 {
     // ----------------------------------------------------------------
     // setup your test
     $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
     $partials = [__CLASS__, 'ReflectionMethod', 'PHPUnit_Framework_TestCase', 'PHPUnit_Framework_TestResult', 'PHPUnit_Framework_TestSuite', 'PHPUnit_TextUI_TestRunner', 'PHPUnit_TextUI_Command'];
     $expectedClass = 'ReflectionMethod';
     $expectedMethod = 'invokeArgs';
     // ----------------------------------------------------------------
     // perform the change
     $result = FilterCodeCaller::from($backtrace, $partials);
     // ----------------------------------------------------------------
     // test the results
     $this->assertInstanceOf(CodeCaller::class, $result);
     $this->assertEquals($expectedClass, $result->getClass());
     $this->assertEquals($expectedMethod, $result->getMethod());
 }