update($release, $target, $work); eq($content, file_get_contents($target), 'binario reemplazado por el nuevo'); ok(is_executable($target), 'queda ejecutable'); rrmdir($release); rrmdir($work); }); Harness::it('self-update aborta ante sha256 inválido sin tocar el binario', function () { $release = tmpdir('release'); $work = tmpdir('work'); write_file($release . '/duckbrain.phar', "contenido nuevo"); write_file($release . '/duckbrain.phar.sha256', 'deadbeef'); $target = $work . '/duckbrain.phar'; write_file($target, 'viejo'); throws(function () use ($release, $target, $work) { (new SelfUpdater(new Toolbox\Console()))->update($release, $target, $work); }); eq('viejo', file_get_contents($target), 'el binario actual queda intacto'); rrmdir($release); rrmdir($work); }); Harness::it('build-phar genera un phar ejecutable con su sha256', function () { $repo = $GLOBALS['g10_repo']; $dist = tmpdir('dist'); exec('DUCKBRAIN_DIST=' . escapeshellarg($dist) . ' bash ' . escapeshellarg($repo . '/scripts/build-phar') . ' 2>&1', $out, $code); eq(0, $code, 'build-phar termina bien: ' . implode("\n", $out)); $phar = $dist . '/duckbrain.phar'; ok(is_file($phar), 'phar generado'); ok(is_file($phar . '.sha256'), 'sha256 publicado'); eq(hash_file('sha256', $phar), trim((string) file_get_contents($phar . '.sha256'))); exec('php ' . escapeshellarg($phar) . ' --version 2>&1', $ver, $vcode); eq(0, $vcode, 'el phar arranca'); ok(str_contains(implode("\n", $ver), 'duckbrain-toolbox'), 'el phar imprime su versión'); rrmdir($dist); });