From bdb208c0799f0497901c91ca4eeaf936a12cf51f Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Thu, 27 Feb 2020 18:40:17 +0100 Subject: [PATCH] [contextualprocess] Split API In order to test some of the internals, split them into Binding.h. This makes the interface visible for tests. The implementation still lives in the same place. While here, adjust the test to the changed **example** which now lists an additional variable. --- src/modules/contextualprocess/Binding.h | 95 +++++++++ .../ContextualProcessJob.cpp | 190 +++++++----------- .../contextualprocess/ContextualProcessJob.h | 2 +- src/modules/contextualprocess/Tests.cpp | 2 +- 4 files changed, 170 insertions(+), 119 deletions(-) create mode 100644 src/modules/contextualprocess/Binding.h diff --git a/src/modules/contextualprocess/Binding.h b/src/modules/contextualprocess/Binding.h new file mode 100644 index 000000000..fce43a65c --- /dev/null +++ b/src/modules/contextualprocess/Binding.h @@ -0,0 +1,95 @@ +/* === This file is part of Calamares - === + * + * Copyright 2017-2020, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +/* This file isn't public API, but is used to express the API that + * the tests for ContextualProcess can work with. + */ +#ifndef CONTEXTUALPROCESSJOB_BINDING_H +#define CONTEXTUALPROCESSJOB_BINDING_H + +#include +#include +#include + +namespace CalamaresUtils +{ +class CommandList; +} +namespace Calamares +{ +class GlobalStorage; +} + +struct ValueCheck : public QPair< QString, CalamaresUtils::CommandList* > +{ + ValueCheck( const QString& value, CalamaresUtils::CommandList* commands ) + : QPair< QString, CalamaresUtils::CommandList* >( value, commands ) + { + } + + // ~ValueCheck() + // + // There is no destructor. + // + // We don't own the commandlist, the binding holding this valuecheck + // does, so don't delete. This is closely tied to (temporaries created + // by) pass-by-value in QList::append(). + + QString value() const { return first; } + CalamaresUtils::CommandList* commands() const { return second; } +}; + +class ContextualProcessBinding +{ +public: + ContextualProcessBinding( const QString& varname ) + : m_variable( varname ) + { + } + + ~ContextualProcessBinding(); + + QString variable() const { return m_variable; } + int count() const { return m_checks.count(); } + + /** + * @brief add commands to be executed when @p value is matched. + * + * Ownership of the CommandList passes to this binding. + */ + void append( const QString& value, CalamaresUtils::CommandList* commands ); + + ///@brief The bound variable has @p value , run the associated commands. + Calamares::JobResult run( const QString& value ) const; + + /** @brief Tries to obtain this binding's value from GS + * + * Stores the value in @p value and returns true if a value + * was found (e.g. @p storage contains the variable this binding + * is for) and false otherwise. + */ + bool fetch( Calamares::GlobalStorage* storage, QString& value ) const; + +private: + QString m_variable; + QList< ValueCheck > m_checks; + CalamaresUtils::CommandList* m_wildcard = nullptr; +}; + + +#endif diff --git a/src/modules/contextualprocess/ContextualProcessJob.cpp b/src/modules/contextualprocess/ContextualProcessJob.cpp index a2aa507ea..b0d7a6743 100644 --- a/src/modules/contextualprocess/ContextualProcessJob.cpp +++ b/src/modules/contextualprocess/ContextualProcessJob.cpp @@ -18,9 +18,7 @@ #include "ContextualProcessJob.h" -#include -#include -#include +#include "Binding.h" #include "CalamaresVersion.h" #include "GlobalStorage.h" @@ -30,120 +28,6 @@ #include "utils/Logger.h" #include "utils/Variant.h" -struct ValueCheck : public QPair< QString, CalamaresUtils::CommandList* > -{ - ValueCheck( const QString& value, CalamaresUtils::CommandList* commands ) - : QPair< QString, CalamaresUtils::CommandList* >( value, commands ) - { - } - - // ~ValueCheck() - // - // There is no destructor. - // - // We don't own the commandlist, the binding holding this valuecheck - // does, so don't delete. This is closely tied to (temporaries created - // by) pass-by-value in QList::append(). - - QString value() const { return first; } - CalamaresUtils::CommandList* commands() const { return second; } -}; - -class ContextualProcessBinding -{ -public: - ContextualProcessBinding( const QString& varname ) - : m_variable( varname ) - { - } - - ~ContextualProcessBinding(); - - QString variable() const { return m_variable; } - int count() const { return m_checks.count(); } - - /** - * @brief add commands to be executed when @p value is matched. - * - * Ownership of the CommandList passes to this binding. - */ - void append( const QString& value, CalamaresUtils::CommandList* commands ) - { - m_checks.append( ValueCheck( value, commands ) ); - if ( value == QString( "*" ) ) - { - m_wildcard = commands; - } - } - - Calamares::JobResult run( const QString& value ) const - { - for ( const auto& c : m_checks ) - { - if ( value == c.value() ) - { - return c.commands()->run(); - } - } - - if ( m_wildcard ) - { - return m_wildcard->run(); - } - - return Calamares::JobResult::ok(); - } - - /** @brief Tries to obtain this binding's value from GS - * - * Stores the value in @p value and returns true if a value - * was found (e.g. @p storage contains the variable this binding - * is for) and false otherwise. - */ - bool fetch( Calamares::GlobalStorage* storage, QString& value ) const - { - value.clear(); - if ( !storage ) - { - return false; - } - if ( m_variable.contains( '.' ) ) - { - QStringList steps = m_variable.split( '.' ); - return fetch( value, steps, 1, storage->value( steps.first() ) ); - } - else - { - value = storage->value( m_variable ).toString(); - return storage->contains( m_variable ); - } - } - -private: - static bool fetch( QString& value, QStringList& selector, int index, const QVariant& v ) - { - if ( !v.canConvert( QMetaType::QVariantMap ) ) - { - return false; - } - const QVariantMap map = v.toMap(); - const QString& key = selector.at( index ); - if ( index == selector.length() ) - { - value = map.value( key ).toString(); - return map.contains( key ); - } - else - { - return fetch( value, selector, index + 1, map.value( key ) ); - } - } - - QString m_variable; - QList< ValueCheck > m_checks; - CalamaresUtils::CommandList* m_wildcard = nullptr; -}; - ContextualProcessBinding::~ContextualProcessBinding() { @@ -154,6 +38,78 @@ ContextualProcessBinding::~ContextualProcessBinding() } } +void +ContextualProcessBinding::append( const QString& value, CalamaresUtils::CommandList* commands ) +{ + m_checks.append( ValueCheck( value, commands ) ); + if ( value == QString( "*" ) ) + { + m_wildcard = commands; + } +} + +Calamares::JobResult +ContextualProcessBinding::run( const QString& value ) const +{ + for ( const auto& c : m_checks ) + { + if ( value == c.value() ) + { + return c.commands()->run(); + } + } + + if ( m_wildcard ) + { + return m_wildcard->run(); + } + + return Calamares::JobResult::ok(); +} + +///@brief Implementation of fetch() for recursively looking up dotted selector parts. +static bool +fetch( QString& value, QStringList& selector, int index, const QVariant& v ) +{ + if ( !v.canConvert( QMetaType::QVariantMap ) ) + { + return false; + } + const QVariantMap map = v.toMap(); + const QString& key = selector.at( index ); + if ( index == selector.length() ) + { + value = map.value( key ).toString(); + return map.contains( key ); + } + else + { + return fetch( value, selector, index + 1, map.value( key ) ); + } +} + + +bool +ContextualProcessBinding::fetch( Calamares::GlobalStorage* storage, QString& value ) const +{ + value.clear(); + if ( !storage ) + { + return false; + } + if ( m_variable.contains( '.' ) ) + { + QStringList steps = m_variable.split( '.' ); + return ::fetch( value, steps, 1, storage->value( steps.first() ) ); + } + else + { + value = storage->value( m_variable ).toString(); + return storage->contains( m_variable ); + } +} + + ContextualProcessJob::ContextualProcessJob( QObject* parent ) : Calamares::CppJob( parent ) { diff --git a/src/modules/contextualprocess/ContextualProcessJob.h b/src/modules/contextualprocess/ContextualProcessJob.h index 3a252d2d3..5ab4b935e 100644 --- a/src/modules/contextualprocess/ContextualProcessJob.h +++ b/src/modules/contextualprocess/ContextualProcessJob.h @@ -27,7 +27,7 @@ #include "utils/PluginFactory.h" -struct ContextualProcessBinding; +class ContextualProcessBinding; class PLUGINDLLEXPORT ContextualProcessJob : public Calamares::CppJob { diff --git a/src/modules/contextualprocess/Tests.cpp b/src/modules/contextualprocess/Tests.cpp index f62726775..8e7000f17 100644 --- a/src/modules/contextualprocess/Tests.cpp +++ b/src/modules/contextualprocess/Tests.cpp @@ -59,6 +59,6 @@ ContextualProcessTests::testProcessListSampleConfig() ContextualProcessJob job; job.setConfigurationMap( CalamaresUtils::yamlMapToVariant( doc ).toMap() ); - QCOMPARE( job.count(), 1 ); // Only "firmwareType" + QCOMPARE( job.count(), 2 ); // Only "firmwareType" and "branding.shortVersion" QCOMPARE( job.count( "firmwareType" ), 4 ); }