From 7711e2bdc3094d617268bac3bd6d26bb9f8ff7b8 Mon Sep 17 00:00:00 2001 From: Michael Karlesky Date: Tue, 17 Sep 2024 16:25:37 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Validating=20nested=20arrays=20i?= =?UTF-8?q?n=20:flags=20&=20:defines?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit YAML anchors and aliases lead to nested arrays in YAML config. Added support for these in `:defines` and `:flags` validation. --- lib/ceedling/config_matchinator.rb | 3 ++- lib/ceedling/configurator_setup.rb | 38 +++++++++++++++++++++++++++--- lib/ceedling/defineinator.rb | 3 ++- lib/ceedling/flaginator.rb | 3 ++- lib/ceedling/tool_executor.rb | 2 +- 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/lib/ceedling/config_matchinator.rb b/lib/ceedling/config_matchinator.rb index 16ed8c48..d9708ab2 100644 --- a/lib/ceedling/config_matchinator.rb +++ b/lib/ceedling/config_matchinator.rb @@ -146,7 +146,8 @@ def matches?(hash:, filepath:, section:, context:, operation:nil) end end - return _values.flatten # Flatten to handle YAML aliases + # Flatten to handle list-nested YAML aliasing (should have already been flattened during validation) + return _values.flatten end ### Private ### diff --git a/lib/ceedling/configurator_setup.rb b/lib/ceedling/configurator_setup.rb index 090d6204..2e60dd87 100644 --- a/lib/ceedling/configurator_setup.rb +++ b/lib/ceedling/configurator_setup.rb @@ -264,6 +264,9 @@ def validate_defines(_config) # Only validate lists of compilation symbols in this block (look for matchers in next block) next if config.class != Array + # Handle any YAML alias referencing causing a nested array + config.flatten!() + # Ensure each item in list is a string config.each do |symbol| if symbol.class != String @@ -294,14 +297,27 @@ def validate_defines(_config) # Skip processing if context isn't present or is present but is not a matcher hash next if matchers.nil? or matchers.class != Hash - walk = @reportinator.generate_config_walk( [:defines, context] ) - # Inspect each test matcher matchers.each_pair do |matcher, symbols| + walk = @reportinator.generate_config_walk( [:defines, context, matcher] ) + + # Ensure container associated with matcher is a list + if symbols.class != Array + msg = "#{walk} entry '#{symbols}' is not a list of compilation symbols but a #{symbols.class.to_s.downcase}" + @loginator.log( msg, Verbosity::ERRORS ) + valid = false + + # Skip further validation if matcher value is not a list of symbols + next + end + + # Handle any YAML alias nesting in array + symbols.flatten!() + # Ensure matcher itself is a Ruby symbol or string if matcher.class != Symbol and matcher.class != String - msg = "#{walk} entry '#{matcher}' is not a string or symbol" + msg = "#{walk} matcher is not a string or symbol" @loginator.log( msg, Verbosity::ERRORS ) valid = false @@ -447,6 +463,9 @@ def validate_flags(_config) # Only validate lists of flags in this block (look for matchers in next block) next if flags.class != Array + # Handle any YAML alias referencing causing a nested array + flags.flatten!() + # Ensure each item in list is a string flags.each do |flag| if flag.class != String @@ -500,6 +519,19 @@ def validate_flags(_config) end walk = @reportinator.generate_config_walk( [:flags, :test, operation, matcher] ) + + # Ensure container associated with matcher is a list + if flags.class != Array + msg = "#{walk} entry '#{flags}' is not a list of command line flags but a #{flags.class.to_s.downcase}" + @loginator.log( msg, Verbosity::ERRORS ) + valid = false + + # Skip further validation if matcher value is not a list of flags + next + end + + # Handle any YAML alias nesting in array + flags.flatten!() # Ensure each item in flags list for matcher is a string flags.each do |flag| diff --git a/lib/ceedling/defineinator.rb b/lib/ceedling/defineinator.rb index fb6ace48..95408866 100644 --- a/lib/ceedling/defineinator.rb +++ b/lib/ceedling/defineinator.rb @@ -40,7 +40,8 @@ def defines(topkey:@topkey, subkey:, filepath:nil, default:[]) defines = @config_matchinator.get_config(primary:topkey, secondary:subkey) if defines == nil then return default - elsif defines.is_a?(Array) then return defines.flatten # Flatten to handle list-nested YAML aliases + # Flatten to handle list-nested YAML aliasing (should have already been flattened during validation) + elsif defines.is_a?(Array) then return defines.flatten elsif defines.is_a?(Hash) arg_hash = { hash: defines, diff --git a/lib/ceedling/flaginator.rb b/lib/ceedling/flaginator.rb index d4bb70b1..20984825 100644 --- a/lib/ceedling/flaginator.rb +++ b/lib/ceedling/flaginator.rb @@ -44,7 +44,8 @@ def flag_down(context:, operation:, filepath:nil, default:[]) flags = @config_matchinator.get_config(primary:@section, secondary:context, tertiary:operation) if flags == nil then return default - elsif flags.is_a?(Array) then return flags.flatten # Flatten to handle list-nested YAML aliases + # Flatten to handle list-nested YAML aliasing (should have already been flattened during validation) + elsif flags.is_a?(Array) then return flags.flatten elsif flags.is_a?(Hash) arg_hash = { hash: flags, diff --git a/lib/ceedling/tool_executor.rb b/lib/ceedling/tool_executor.rb index 22c1152c..aee674c5 100644 --- a/lib/ceedling/tool_executor.rb +++ b/lib/ceedling/tool_executor.rb @@ -104,7 +104,7 @@ def build_arguments(tool_name, config, *args) # Iterate through each argument - # The yaml blob array needs to be flattened so that yaml substitution is handled + # The yaml blob array needs to be flattened so that yaml alias substitution is handled # correctly as it creates a nested array when an anchor is dereferenced config.flatten.each do |element| argument = ''