1# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
14# frozen_string_literal: true
15
16module Generator
17  class Parser
18    def initialize(data, output, src_dir, skip_header)
19      @data = data
20      @output = output
21      @src_dir = src_dir
22
23      # TODO: add validation of input YAML to avoid additional checking in code
24
25      LOG.info 'Generator created'
26      LOG.debug "@data first 3 keys are: '#{data.keys.first(3)}'"
27
28      # data - YAML:
29      #  tests: Generator::TESTS
30      #  definitions: Generator::DEFINITIONS
31
32      # Tests definitions
33      @tests = @data[Generator::TESTS]
34      # some predefined templates as headers, prefixes, postfixes, etc.
35      raise "'#{Generator::DEFINITIONS}' is not found in main yaml" unless @data.key? Generator::DEFINITIONS
36      @predefined = Definitions.new @data[Generator::DEFINITIONS]
37      @skip_header = skip_header
38    end
39
40    def parse(skip)
41      start_time = Time.now
42      updated_tests = @tests.flat_map do |test|
43        if test.key? Generator::TESTS_INCLUDE
44          file_name = test[Generator::TESTS_INCLUDE]
45          included_data = YAML.load_file("#{@src_dir}/#{file_name}")
46          if !skip
47            res = JSON::Validator.fully_validate("#{@src_dir}/yaml-schema.json", included_data)
48            unless res.empty?
49              puts "Template '#{file_name}' contains several errors:"
50              puts res
51              raise "Schema validation error, please update template '#{file_name}' to match schema to generate tests"
52            end
53          end
54
55          # Add definitions to each test group from file.
56          included_data[Generator::TESTS].map do |single_test|
57            single_test[Generator::DEFINITIONS] = included_data[Generator::DEFINITIONS]
58            single_test
59          end
60          included_data[Generator::TESTS]
61        else
62          test
63        end
64      end
65
66      @tests = updated_tests
67
68      test_has_only_key = false
69      command_has_only_key = false
70      @tests.each do |raw_test|
71        test_has_only_key ||= raw_test.key?(Generator::TEST_ONLY) && raw_test[Generator::TEST_ONLY]
72        raw_test[Generator::TEST_COMMANDS].each do |command|
73          command_has_only_key ||= command.key?(Generator::TEST_COMMAND_ONLY) && command[Generator::TEST_COMMAND_ONLY]
74        end
75      end
76      LOG.debug "test_has_only_key = #{test_has_only_key}"
77      LOG.debug "command_has_only_key = #{command_has_only_key}"
78      options = { test_has_only_key: test_has_only_key, command_has_only_key: command_has_only_key }
79
80      LOG.debug options
81
82      # Generated test directory
83      FileUtils.rm_rf @output if File.exist? @output
84      FileUtils.mkdir_p @output unless File.exist? @output
85      iterate_tests options
86      LOG.info "Tests generation done in #{Time.now - start_time} sec"
87    end
88
89    def iterate_tests(options)
90      LOG.debug('Iterate over all tests')
91      @tests.each do |raw_test|
92        if options[:test_has_only_key]
93          process = raw_test.key?(Generator::TEST_ONLY) && raw_test[Generator::TEST_ONLY] || options[:command_has_only_key]
94          LOG.debug "'only:' is defined for some test, process current: #{process}"
95          if process
96            # Process all commands
97            test = Test.new raw_test, @predefined, options[:command_has_only_key], @output, @skip_header
98            test.parse
99          end
100        else
101          LOG.debug "'only:' is not defined for test, process current: true"
102          # Process commands, if it has only, to only them should be processed
103          test = Test.new raw_test, @predefined, options[:command_has_only_key], @output, @skip_header
104          test.parse
105        end
106
107      end
108    end
109  end
110end
111