Revision control
++ #!/usr/bin/env perl
++ # Copyright (C) 2017 The Qt Company Ltd.
++ # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++ use 5.010;
++ use strict;
++ use warnings;
++
++ =head1 NAME
++
++ coveragerunner_testcocoon - helper script to run coverage analysis after build (tool used is TestCocoon)
++
++ =head1 SYNOPSIS
++
++ # Run code coverage analysis
++ $ ./coveragerunner_testcocoon --qtmodule-dir path/to/module --qtmodule-name modulename --qtcoverage-tests_output path/to/output/folder/tests_database.csmes"
++
++ # Example launch script for a qt module (ie qtbase)
++ # ./coveragerunner_testcocoon --qtmodule-dir path/to/qtbase --qtmodule-name qtbase --qtcoverage-tests_output "$HOME/qtbase/alltests.csmes"
++
++ # Will generate:
++ #
++ # $HOME/qtbase/qtbase-coverage_report-<currentdatetime>.xml
++ # $HOME/qtbase/qtbase-coverage_global-<currentdatetime>.csmes
++ #
++
++ This script depends on auto tests run with testrunner script. It is designed to integrate with Qt configured
++ with -testcocoon option and testrunner run with the testcocoon plugin loaded.
++
++ Required qtcoverage-tests_output
++ generated from testrunner. This file is renamed with unique name to avoid overwriting it.
++
++ =head1 OPTIONS
++
++ =over
++
++ =item B<--help>
++
++ Print this message.
++
++ =item B<--qtmodule-dir> <directory>
++
++ Required. Path to Qt5 module to analyze.
++
++ =item B<--qtmodule-name> <value>
++
++ Required. Name of Qt5 module to analyze.
++
++ =item B<--qtcoverage-tests-output> <directory>
++
++ Required. Full path to the csmes database gathering tests results.
++
++ =back
++
++ =cut
++
++ use FindBin;
++ use lib "$FindBin::Bin/../lib/perl5";
++
++ package QtQA::App::CoverageRunnerTestCocoon;
++ use base qw(QtQA::TestScript);
++
++ use Carp;
++ use Getopt::Long qw(GetOptionsFromArray);
++ use English qw( -no_match_vars );
++ use File::Basename;
++ use File::Spec::Functions;
++ use Pod::Usage qw( pod2usage );
++ use autodie;
++
++ use POSIX qw/strftime/;
++ use File::Copy;
++ use File::Find::Rule;
++
++ sub new
++ {
++ my ($class) = @_;
++
++ my $self = $class->SUPER::new;
++ bless $self, $class;
++ return $self;
++ }
++
++ sub run
++ {
++ my ($self, @args) = @_;
++
++ my $qt_gitmodule_dir;
++ my $qt_gitmodule;
++ my $testcocoon_tests_output;
++
++ GetOptionsFromArray( \@args,
++ 'help|?' => sub { pod2usage(1) },
++ 'qt-gitmodule-dir=s' => \$qt_gitmodule_dir,
++ 'qt-gitmodule=s' => \$qt_gitmodule,
++ 'qtcoverage-tests-output=s' => \$testcocoon_tests_output,
++ ) || pod2usage(2);
++
++ my $currentdatetime = strftime('%Y%m%d-%H%M', localtime);
++
++ if (! -f $testcocoon_tests_output) {
++ confess "$testcocoon_tests_output does not exist. Either the tests have not been run or coverage was not enabled at build time";
++ }
++
++ my $coverage_dir = dirname($testcocoon_tests_output);
++
++ # Named unique output files
++ my $xml_report = $qt_gitmodule . "_coverage_report-" . $currentdatetime . ".xml";
++ my $csmes_source = $qt_gitmodule . "_coverage_src-" . $currentdatetime . ".csmes";
++ my $csmes_tests = $qt_gitmodule . "_coverage_unittests-" . $currentdatetime . ".csmes";
++ my $csmes_global = $qt_gitmodule . "_coverage_global-" . $currentdatetime . ".csmes";
++
++ $xml_report = catfile( $coverage_dir, $xml_report );
++ $csmes_source = catfile( $coverage_dir, $csmes_source );
++ $csmes_tests = catfile( $coverage_dir, $csmes_tests );
++ $csmes_global = catfile( $coverage_dir, $csmes_global );
++
++ # Rename global tests csmes file with unique name
++ move($testcocoon_tests_output, $csmes_tests) or confess "move $testcocoon_tests_output: $!";
++
++ my $qt_git_qtbase_dir =
++ ($qt_gitmodule eq 'qtbase') ? $qt_gitmodule_dir
++ : ($qt_gitmodule eq 'qt5') ? catfile($qt_gitmodule_dir, 'qtbase')
++ : catfile($qt_gitmodule_dir, '..', 'qtbase');
++
++ # Get all sources files csmes gathered in a global database (from lib and plugins folder)
++ my $qt_git_qtbase_libdir = catfile($qt_git_qtbase_dir, 'lib');
++ print "Gather all library files covered in a global database\n";
++
++ my $qt_git_qtbase_pluginsdir = catfile($qt_git_qtbase_dir, 'plugins');
++ my $qt_git_qtbase_importsdir = catfile($qt_git_qtbase_dir, 'imports');
++
++ my @allcsmes = File::Find::Rule->file()->name( '*.csmes' )->in($qt_git_qtbase_libdir);
++ push @allcsmes, File::Find::Rule->file()->name( '*.csmes' )->in($qt_git_qtbase_pluginsdir);
++ push @allcsmes, File::Find::Rule->file()->name( '*.csmes' )->in($qt_git_qtbase_importsdir);
++ @allcsmes = map { canonpath($_) } sort(@allcsmes);
++
++ print "List of all source files in coverage\n";
++
++ foreach my $csmes (@allcsmes) {
++ print "$csmes\n";
++ if (-e $csmes_source) {
++ $self->exe('cmmerge',
++ '--append',
++ "--output=$csmes_source",
++ $csmes
++ );
++ } else {
++ copy($csmes, $csmes_source) or confess "copy $csmes: $!";
++ }
++ }
++
++ print "End of list\n";
++
++ # Create global database
++ move($csmes_source, $csmes_global) or confess "move $csmes_source: $!";
++
++ # Merge tests into global
++ $self->exe('cmmerge',
++ '--append',
++ "--output=$csmes_global",
++ $csmes_tests
++ );
++
++ # Delete the tests csmes to save space.
++ unlink($csmes_tests) or confess "unlink $csmes_tests: $!";
++
++ # Generate report
++ $self->exe('cmreport',
++ "--csmes=$csmes_global",
++ "--xml=$xml_report",
++ '--select=.*',
++ '--source=all',
++ '--source-sort=name',
++ '--global=all'
++ );
++
++ # Compress global csmes to save space
++ $self->exe('gzip',
++ $csmes_global);
++
++ # Create hmtl reports
++ my $xml2html = catfile( $FindBin::Bin, 'xml2html_testcocoon.pl' );
++ $xml2html = 'xml2html_testcocoon' if (defined $ENV{ TESTING_COVERAGERUNNER });
++ $self->exe($xml2html,
++ '--xml',
++ $xml_report,
++ '--module',
++ $qt_gitmodule,
++ '--output',
++ $coverage_dir,
++ '--include',
++ catfile($qt_gitmodule_dir, 'src'),
++ '--exclude',
++ catfile($qt_gitmodule_dir, 'src', '3rdparty')
++ );
++
++ return;
++ }
++
++ QtQA::App::CoverageRunnerTestCocoon->new( )->run( @ARGV ) if (!caller);
++ 1;
++