use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
use std::thread;
use php_parser_rs::lexer::Lexer;
enum TestResult {
Success,
Error(String),
}
#[test]
fn php_standard_library() {
test_repository(
"php-standard-library",
"https://github.com/azjezz/psl.git",
&[],
);
}
#[test]
fn laravel_framework() {
test_repository(
"laravel-framework",
"https://github.com/laravel/framework",
&[
"tests/Foundation/fixtures/bad-syntax-strategy.php",
],
);
}
#[test]
fn hyperf_framework() {
test_repository(
"hyperf-framework",
"https://github.com/hyperf/hyperf",
&[
"vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php",
"vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php",
"vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php",
],
);
}
#[test]
fn symfony_framework() {
test_repository(
"symfony-framework",
"https://github.com/symfony/symfony",
&[
"src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/Fixtures/proxy-implem.php",
"src/Symfony/Component/Config/Tests/Fixtures/ParseError.php",
"src/Symfony/Component/VarExporter/LazyProxyTrait.php",
"src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/xml_with_wrong_ext.php",
],
);
}
#[test]
fn nikic_php_parser() {
test_repository(
"nikic/PHP-Parser",
"https://github.com/nikic/PHP-Parser",
&[
"vendor/ircmaxell/php-yacc/examples/00-basic-usage/parser.template.php",
"vendor/ircmaxell/php-yacc/examples/01-expression-support/parser.template.php",
"vendor/ircmaxell/php-yacc/examples/02-complex-expression-support/parser.template.php",
"vendor/ircmaxell/php-yacc/examples/10-php7/parser.kmyacc.php",
"vendor/ircmaxell/php-yacc/examples/10-php7/parser.phpyacc.php",
"vendor/ircmaxell/php-yacc/examples/10-php7/parser.template.php",
"vendor/ircmaxell/php-yacc/examples/20-custom-parser/parser.kmyacc.php",
"vendor/ircmaxell/php-yacc/examples/20-custom-parser/parser.phpyacc.php",
"vendor/ircmaxell/php-yacc/examples/20-custom-parser/parser.template.php",
],
);
}
#[test]
fn yii_framework() {
test_repository(
"yii-framework",
"https://github.com/yiisoft/yii2",
&[
"vendor/sebastian/diff/tests/ParserTest.php",
],
);
}
#[test]
fn spiral_framework() {
test_repository(
"spiral-framework",
"https://github.com/spiral/framework",
&[
"src/Core/tests/Fixtures/CorruptedClass.php",
"src/Tokenizer/tests/Classes/BrokenClass.php",
],
);
}
#[test]
fn mezzio_framework() {
test_repository(
"mezzio-framework",
"https://github.com/mezzio/mezzio",
&[
"vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php",
"vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php",
"vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php",
],
);
}
#[test]
fn symfony_polyfill() {
test_repository(
"symfony-polyfill",
"https://github.com/symfony/polyfill",
&[],
);
}
#[test]
fn madelineproto() {
test_repository(
"MadelineProto",
"https://github.com/danog/MadelineProto",
&[],
);
}
#[test]
fn phabel() {
test_repository(
"phabel",
"https://github.com/phabelio/phabel",
&[
"tests/TargetFuture/AwaitTest.php",
],
);
}
#[test]
fn psalm() {
test_repository("psalm", "https://github.com/vimeo/psalm", &[]);
}
#[test]
fn phpstan_bin() {
test_repository("phpstan", "https://github.com/phpstan/phpstan", &[]);
}
#[test]
fn phpstan_src() {
test_repository(
"phpstan-src",
"https://github.com/phpstan/phpstan-src",
&[
"tests/PHPStan/Rules/Classes/data/invalid-promoted-properties.php",
"tests/PHPStan/Rules/Classes/data/trait-use-error.php",
"tests/PHPStan/Analyser/data/multipleParseErrors.php",
"tests/PHPStan/Analyser/data/parse-error.php",
"tests/PHPStan/Levels/data/namedArguments.php",
"tests/PHPStan/Rules/Classes/data/enum-sanity.php",
"tests/PHPStan/Rules/Classes/data/instanceof.php",
"tests/PHPStan/Rules/Functions/data/arrow-function-intersection-types.php",
"tests/PHPStan/Rules/Functions/data/closure-intersection-types.php",
"tests/PHPStan/Rules/Functions/data/intersection-types.php",
"tests/PHPStan/Rules/Methods/data/abstract-method.php",
"tests/PHPStan/Rules/Methods/data/call-method-in-enum.php",
"tests/PHPStan/Rules/Methods/data/intersection-types.php",
"tests/PHPStan/Rules/Methods/data/missing-method-impl.php",
"tests/PHPStan/Rules/Methods/data/named-arguments.php",
"tests/PHPStan/Rules/Methods/data/named-arguments.php",
"tests/PHPStan/Rules/Functions/data/closure-typehints.php",
"tests/PHPStan/Rules/Properties/data/intersection-types.php",
"tests/PHPStan/Rules/Properties/data/read-only-property-phpdoc-and-native.php",
"tests/PHPStan/Rules/Properties/data/read-only-property.php",
"tests/PHPStan/Analyser/data/bug-7135.php",
"tests/PHPStan/Rules/Classes/data/first-class-instantiation-callable.php",
"tests/PHPStan/Rules/Classes/data/instantiation-callable.php",
],
);
}
#[test]
fn rector_bin() {
test_repository(
"rector",
"https://github.com/rectorphp/rector",
&[
"e2e/parse-php7-code/src/Foo.php",
],
);
}
#[test]
fn rector_src() {
test_repository(
"rector-src",
"https://github.com/rectorphp/rector-src",
&[
"build/target-repository/e2e/parse-php7-code/src/Foo.php",
],
);
}
#[test]
fn composer() {
test_repository("composer", "https://github.com/composer/composer", &[]);
}
#[test]
fn wordpress() {
test_repository("wordpress", "https://github.com/WordPress/WordPress", &[]);
}
#[test]
fn chubbyphp_framework() {
test_repository(
"chubbyphp-framework",
"https://github.com/chubbyphp/chubbyphp-framework",
&[],
);
}
#[test]
fn silverstripe_framework_core() {
test_repository(
"silverstripe-framework",
"https://github.com/silverstripe/silverstripe-framework",
&[],
);
}
#[test]
fn silverstripe_framework_cms() {
test_repository(
"silverstripe-cms",
"https://github.com/silverstripe/silverstripe-cms",
&[],
);
}
#[test]
fn roundcubemail_web() {
test_repository(
"roundcubemail",
"https://github.com/roundcube/roundcubemail",
&[],
);
}
#[test]
fn phpmyadmin_web() {
test_repository(
"phpmyadmin",
"https://github.com/phpmyadmin/phpmyadmin",
&[
"vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php",
"vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php",
"vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php",
],
);
}
#[test]
fn phpbb() {
test_repository("phpbb", "https://github.com/phpbb/phpbb", &[]);
}
#[test]
fn drupal() {
test_repository("drupal", "https://github.com/drupal/core", &[]);
}
#[test]
fn api_platform() {
test_repository("api-platform", "https://github.com/api-platform/core", &[
"vendor/doctrine/mongodb-odm/lib/Doctrine/ODM/MongoDB/Aggregation/Stage/GraphLookup/Match.php",
"vendor/doctrine/mongodb-odm/lib/Doctrine/ODM/MongoDB/Aggregation/Stage/Match.php",
]);
}
#[test]
fn joomla() {
test_repository(
"joomla",
"https://github.com/joomla/joomla-cms",
&[
"libraries/vendor/hoa/console/Chrome/Text.php",
"libraries/vendor/phpunit/php-code-coverage/tests/_files/Crash.php",
],
);
}
#[test]
fn prestashop() {
test_repository(
"prestashop",
"https://github.com/PrestaShop/PrestaShop",
&[
"vendor/marcusschwarz/lesserphp/lessify.inc.php",
"vendor/greenlion/php-sql-parser/libs/codesniffer/PhOSCo/Sniffs/Commenting/FileCommentSniff.php",
"vendor/phpunit/php-code-coverage/tests/_files/Crash.php"
],
);
}
#[test]
fn sylius() {
test_repository(
"sylius",
"https://github.com/Sylius/Sylius",
&[
"vendor/phpunit/php-code-coverage/tests/_files/Crash.php",
],
);
}
#[test]
fn doctrine_orm() {
test_repository("doctrine-orm", "https://github.com/doctrine/orm", &[]);
}
#[test]
fn doctrine_dbal() {
test_repository("doctrine-dbal", "https://github.com/doctrine/dbal", &[]);
}
#[test]
fn phpunit() {
test_repository(
"phpunit",
"https://github.com/sebastianbergmann/phpunit",
&[],
);
}
fn test_repository(name: &str, repository: &str, ignore: &[&str]) {
let manifest = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let out_dir = manifest.join("target").join("third-party");
if !out_dir.exists() {
fs::create_dir(&out_dir).unwrap();
}
let out_path = out_dir.join(name);
if !out_path.exists() {
let output = Command::new("git")
.arg("clone")
.arg("--depth")
.arg("1")
.arg(repository)
.arg(&out_path)
.output()
.expect("failed to run git.");
if !output.status.success() {
panic!("failed to clone repository: {:#?}", output)
}
}
let composer_json = out_path.join("composer.json");
let autoload = out_path.join("vendor").join("autoload.php");
if composer_json.exists() && !autoload.exists() {
let output = Command::new("composer")
.arg("install")
.arg("--ignore-platform-reqs")
.arg("--no-plugins")
.arg("--no-scripts")
.arg("--no-interaction")
.arg("--prefer-dist")
.current_dir(&out_path)
.output()
.expect("failed to run composer");
if !output.status.success() {
panic!(
"failed to run composer install in repository: {:#?}",
output
);
}
}
let entries = read_directory(name, out_path.clone(), out_path, ignore);
let thread = thread::Builder::new()
.stack_size(16 * 1024 * 1024)
.name(name.to_string())
.spawn(move || {
let thread = thread::current();
let thread_name = thread.name().unwrap();
let mut results = vec![];
for (name, filename) in entries {
let code = std::fs::read(filename).unwrap();
match Lexer::new().tokenize(&code) {
Ok(tokens) => match php_parser_rs::construct(&tokens) {
Ok(_) => {
results.push(TestResult::Success);
}
Err(error) => {
results.push(TestResult::Error(format!(
"❌ [{thread_name}][{name}]: {error} ({error:?})"
)));
}
},
Err(error) => {
results.push(TestResult::Error(format!(
"❌ [{thread_name}][{name}]: {error} ({error:?})"
)));
}
}
}
results
});
let result = thread
.unwrap_or_else(|e| panic!("failed to spawn thread: {:#?}", e))
.join()
.unwrap_or_else(|e| panic!("failed to join thread: {:#?}", e));
let mut fail = false;
result
.iter()
.map(|result| match result {
TestResult::Error(message) => {
fail = true;
println!("{}", message);
}
TestResult::Success => {}
})
.for_each(drop);
if fail {
panic!();
}
}
fn read_directory(
name: &str,
root: PathBuf,
directory: PathBuf,
ignore: &[&str],
) -> Vec<(String, PathBuf)> {
let mut results = vec![];
let mut entries = fs::read_dir(directory)
.unwrap()
.flatten()
.map(|entry| entry.path())
.collect::<Vec<PathBuf>>();
entries.sort();
let ignored_prefixes = [
"vendor/symfony",
"vendor/doctrine/orm",
"vendor/doctrine/dbal",
"vendor/api-platform/core",
"vendor/rector/rector",
"vendor/phpstan/phpstan",
"vendor/phpstan/php-8-stubs",
"vendor/jetbrains/phpstorm-stubs",
];
for entry in entries {
let path = &entry
.as_path()
.strip_prefix(&root)
.unwrap()
.to_str()
.unwrap();
if name != "php-standard-library" {
if let Some(_) = ignored_prefixes.iter().find(|p| path.starts_with(*p)) {
continue;
}
}
if entry.is_dir() {
results.append(&mut read_directory(name, root.clone(), entry, ignore));
continue;
}
if entry.extension().unwrap_or_default() == "php" && !ignore.contains(path) {
let fullname_string = &entry.to_string_lossy();
let name = fullname_string
.strip_prefix(root.to_str().unwrap())
.unwrap();
results.push((name.to_string(), entry));
}
}
results
}