matkoniecz/CartoCSSHelper

View on GitHub
lib/cartocss_helper/validator.rb

Summary

Maintainability
B
6 hrs
Test Coverage
# frozen_string_literal: true

require_relative 'heuristic.rb'
require_relative 'image_generator.rb'
require_relative 'configuration.rb'
require_relative 'tag_lister.rb'

include CartoCSSHelper::Heuristic
include CartoCSSHelper::Configuration

module CartoCSSHelper
  module Validator
    def run_tests(git_branch)
      run_dy_test(git_branch)
      run_missing_name_test(git_branch)
      run_expected_rendering_test(git_branch, true)
      run_closed_way_test(git_branch)
      run_expected_rendering_test(git_branch)
      run_unwanted_name_test(git_branch)
    end

    def run_expected_rendering_test(git_branch, quick_and_more_prone_to_errors = false)
      Git.checkout git_branch
      puts 'unexpectedly rendered/unrendered keys:'
      compare_expected_with_real_rendering(quick_and_more_prone_to_errors)
      puts
    end

    def run_missing_name_test(git_branch)
      Git.checkout git_branch
      puts 'Check whatever names are displayed:'
      run_global_check(:check_missing_names)
      puts
    end

    def run_unwanted_name_test(git_branch)
      Git.checkout git_branch
      puts 'Check whatever names are displayed:'
      run_global_check(:check_unwanted_names)
      puts
    end

    def run_dy_test(git_branch)
      Git.checkout git_branch
      puts "bad dy values (tall names like 'É' are not displayed, short names like 'a' are):"
      run_global_check(:check_dy)
      puts
    end

    def run_closed_way_test(git_branch)
      Git.checkout git_branch
      puts 'failed display of closed way, unlosed way works:'
      run_global_check(:check_problems_with_closed_line)
      puts
    end

    def compare_expected_with_real_rendering(quick_and_more_prone_to_errors = false)
      list_of_documented = CartoCSSHelper::Configuration.get_style_specific_data.list_of_documented_tags
      info = Info.new
      list_of_rendered = info.get_render_state_of_tags(quick_and_more_prone_to_errors)

      puts 'ensure_that_tags_documented_and_rendered_have_the_same_state'
      ensure_that_tags_documented_and_rendered_have_the_same_state(list_of_documented, list_of_rendered)

      puts 'ensure_that_all_rendered_tags_are_documented'
      ensure_that_all_rendered_tags_are_documented(list_of_documented, list_of_rendered)

      puts 'ensure_that_all_documented_are_really_rendered'
      ensure_that_all_documented_are_really_rendered(list_of_documented, list_of_rendered)
    end

    def ensure_that_tags_documented_and_rendered_have_the_same_state(list_of_documented, list_of_rendered)
      list_of_rendered.each do |tag_info|
        compare_expected_with_tag_data list_of_documented, tag_info
      end
    end

    def ensure_that_all_rendered_tags_are_documented(list_of_documented, list_of_rendered)
      list_of_rendered.each do |tag_info|
        next if is_tag_documented(list_of_documented, tag_info.key, tag_info.value)
        puts 'documented'
        puts "\tmissing"
        puts 'real'
        print "\t"
        tag_info.print
        puts
      end
    end

    def ensure_that_all_documented_are_really_rendered(list_of_documented, list_of_rendered)
      list_of_documented.each do |documented|
        if Info.get_expected_state(documented.key, documented.value) == :ignored
          next
        end
        next if is_tag_documented(list_of_rendered, documented.key, documented.value)
        puts 'documented'
        print "\t"
        documented.print
        puts 'real'
        puts "\tmissing"
        puts
      end
    end

    def is_tag_documented(list, key, value)
      list.each do |tag_info|
        next unless key == tag_info.key
        return true if value == tag_info.value
      end
      return false
    end

    def compare_expected_with_tag_data(list_of_expected, tag_info)
      list_of_expected.each do |expected|
        next unless expected.key == tag_info.key
        next unless expected.value == tag_info.value
        if expected.equal? tag_info
          puts 'expected'
          print "\t"
          expected.print
          puts 'real'
          print "\t"
          tag_info.print
          puts
        end
        return
      end
    end

    def run_global_check(function)
      Heuristic.get_tags.each do |element|
        key = element[0]
        value = element[1]
        state = Info.get_expected_state(key, value)
        tags = { key => value }
        next if state == :ignore
        if state == :composite
          tags.merge!(Info.get_expected_composite(key, value))
        end
        (Configuration.get_max_z..Configuration.get_max_z).each do |zlevel| # get_min_z should be used - but as renderer is extremely slow this hack was used TODO
          send(function, tags, zlevel)
        end
      end
    end

    def check_problems_with_closed_line(tags, zlevel, on_water = false)
      way = Scene.new(tags, zlevel, on_water, 'way', true)
      closed_way = Scene.new(tags, zlevel, on_water, 'closed_way', true)
      empty = Scene.new({}, zlevel, on_water, 'node', true)
      if way.is_output_different(empty)
        puts tags unless closed_way.is_output_different(empty)
      end
    end

    def check_missing_names(tags, zlevel, interactive = false, on_water = false)
      not_required = CartoCSSHelper::Configuration.get_style_specific_data.name_label_is_not_required
      return if not_required.include?(tags)
      ['node', 'closed_way', 'way'].each do |type|
        next if not_required.include?(tags.merge({ type: type }))
        unless is_object_displaying_anything_as_this_object_type tags, zlevel, on_water, type
          # puts key+"="+value+" - not displayed as node on z#{zlevel}"
          next
        end
        tags.delete('name') if tags['name'] != nil
        unless is_object_displaying_name_as_this_object_type tags, 'a', zlevel, on_water, type
          puts "#{tags} - label is missing on z#{zlevel} #{type}"
          next
        end
      end
    end

    def check_unwanted_names(tags, zlevel, interactive = false, on_water = false)
      ['node', 'closed_way', 'way'].each do |type|
        not_required = CartoCSSHelper::Configuration.get_style_specific_data.name_label_is_not_required
        next unless not_required.include?(tags) || not_required.include?(tags.merge({ type: type }))
        unless is_object_displaying_anything_as_this_object_type tags, zlevel, on_water, type
          # puts key+"="+value+" - not displayed as node on z#{zlevel}"
          next
        end
        tags.delete('name') if tags['name'] != nil
        if is_object_displaying_name_as_this_object_type tags, 'a', zlevel, on_water, type
          puts "#{tags} - label is unxpectedly displayed on z#{zlevel} #{type}"
        end
      end
    end

    def check_dy(tags, zlevel, interactive = false, on_water = false)
      unless is_object_displaying_anything_as_node tags, zlevel, on_water
        # puts key+"="+value+" - not displayed as node on z#{zlevel}"
        return
      end
      unless is_object_displaying_name_as_node tags, 'a', zlevel, on_water
        # puts key+"="+value+" - label is missing on z#{zlevel} nodes"
        return
      end
      test_name = 'ÉÉÉÉÉÉ ÉÉÉÉÉÉ ÉÉÉÉÉÉ'
      until is_object_displaying_name_as_node tags, test_name, zlevel, on_water
        puts "#{tags} - name is missing for name '#{test_name}' on z#{zlevel}"
        if interactive
          puts 'press enter'
          gets
        else
          return
        end
        with_name = Scene.new({ key => value, 'name' => test_name }, zlevel, on_water, 'node', true)
        with_name.flush_cache
        puts 'calculating'
      end
      # puts key+"="+value+" - name is OK for name '#{name}'"
    end

    def is_object_displaying_name_as_this_object_type(tags, name, zlevel, on_water, type)
      name_tags = tags.merge({ 'name' => name })
      with_name = Scene.new(name_tags, zlevel, on_water, type, true)
      nameless_tags = tags
      nameless = Scene.new(nameless_tags, zlevel, on_water, type, true)
      return with_name.is_output_different(nameless)
    end

    def is_object_displaying_name_as_node(tags, name, zlevel, on_water)
      is_object_displaying_name_as_this_object_type(tags, name, zlevel, on_water, 'node')
    end

    def is_object_displaying_anything_as_this_object_type(tags, zlevel, on_water, type)
      object = Scene.new(tags, zlevel, on_water, type, true)
      empty = Scene.new({}, zlevel, on_water, type, true)
      return object.is_output_different(empty)
    end

    def is_object_displaying_anything_as_node(tags, zlevel, on_water)
      return is_object_displaying_anything_as_this_object_type(tags, zlevel, on_water, 'node')
    end
  end
end