123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- # SPDX-FileCopyrightText: 2024 mio <stigma@disroot.org>
- # SPDX-License-Identifier: BSD-3-Clause
- # A rather slow (and not necessarily correct*) method of testing luce.
- # It retrieves a list of shards from shardbox.org (by category), and
- # attempts to parse any markdown file found in the shard's repository.
- #
- # After each test there is a delay (SHARD_TEST_DELAY_SECONDS), and
- # once a category has been complete there is another delay
- # (CATEGORY_TEST_DELAY_SECONDS).
- #
- # In its current incarnation, this script may take a few hours to
- # complete.
- #
- # * This only checks whether luce raises an exception, not if the HTML
- # generated is correct.
- require "file_utils"
- require "http/client"
- require "yaml"
- require "../src/luce.cr"
- SHARD_TEST_DELAY_SECONDS = 8
- CATEGORY_TEST_DELAY_SECONDS = 16
- enum TestResultType
- Success
- Skipped
- Failed
- end
- record TestResult, type : TestResultType, message : String
- # tip to update:
- # git clone https://github.com/shardbox/catalog --depth 1
- # cd catalog/catalog
- # find -printf "%f\n" | sort | cut -d'.' -f1
- SHARDBOX_CATEGORIES = [
- "Algorithms_and_Data_structures",
- "Api_Builders",
- "Audio",
- "Blockchain",
- "Caching",
- "C_bindings",
- "CLI_Applications",
- "CLI_Builders",
- "CLI_Utils",
- "Code_Analysis_and_Metrics",
- "Compression",
- "Concurrency",
- "Configuration",
- "Converters",
- "Cryptography",
- "Database_Drivers_Clients",
- "Database_Tools",
- "Data_Formats",
- "Data_Generators",
- "Debugging",
- "Dependency_Injection",
- "Development_Tools",
- "Email",
- "Environment_Management",
- "Examples_and_funny_stuff",
- "Feature_Flipping",
- "Framework_Components",
- "Game_Development",
- "GUI_Development",
- "GUI_library",
- "HTML_Builders",
- "HTML_XML_Parsing",
- "HTTP",
- "Image_processing",
- "Implementations_Compilers",
- "Internationalization",
- "Logging_and_monitoring",
- "Machine_Learning",
- "Markdown_Text_Processors",
- "Misc",
- "Natural_Language",
- "Networking",
- "Network_Protocols",
- "ORM_ODM_Extensions",
- "Package_Management",
- "Parser_Generators",
- "Processes_and_Threads",
- "Project_Generators",
- "Queues_and_Messaging",
- "Routing",
- "Scheduling",
- "Science_and_Data_analysis",
- "Search",
- "Serverless_Computing",
- "System",
- "Task_management",
- "Template_Engine",
- "Testing",
- "Third-party_APIs",
- "Time_Date",
- "Uncategorized",
- "Validation",
- "Web_Applications",
- "Web_Frameworks",
- "Web_Servers",
- ]
- def fetch_category_yaml(category : String) : YAML::Any?
- puts "Downloading #{category} YAML file..."
- yaml_file_res = HTTP::Client.get "https://raw.githubusercontent.com/shardbox/catalog/master/catalog/#{category}.yml"
- unless yaml_file_res.success?
- STDERR.puts "Failed to download YAML file for category: #{category}"
- STDERR.puts "#{yaml_file_res.status} (#{yaml_file_res.status_code}): #{yaml_file_res.status_message}"
- return nil
- end
- YAML.parse(yaml_file_res.body)
- end
- def test_shard(shard : YAML::Any) : TestResult
- url = if shard["github"]?
- "https://github.com/#{shard["github"]}"
- elsif shard["gitlab"]?
- "https://gitlab.com/#{shard["gitlab"]}"
- elsif shard["bitbucket"]?
- "https://bitbucket.org/#{shard["bitbucket"]}"
- elsif shard["git"]?
- "#{shard["git"]}"
- else
- raise "Unsupported shard host: #{shard}"
- end
- HTTP::Client.head(url) do |response|
- return TestResult.new(TestResultType::Skipped, "404: #{url}") unless response.success?
- end
- dir = File.basename(url)
- # TODO: Get terminal width and truncate url
- puts " Cloning git repository: #{url}"
- Process.run("git", ["clone", url, "--depth=1", dir])
- done = Channel(Nil).new
- Dir.glob("#{dir}/**/*.md").each do |md|
- spawn do
- contents = File.read(md)
- Luce.to_html(contents, extension_set: Luce::ExtensionSet::GITHUB_WEB)
- done.send(nil)
- end
- select
- when res = done.receive
- break
- when timeout(2.minutes)
- return TestResult.new(TestResultType::Failed, "#{shard}\n Reason: Timed out")
- end
- rescue ex
- return TestResult.new(TestResultType::Failed, "#{shard}\n Reason: #{ex}")
- end
- sleep SHARD_TEST_DELAY_SECONDS
- TestResult.new(TestResultType::Success, "")
- ensure
- FileUtils.rm_rf(dir) unless dir.nil?
- end
- def main(args = ARGV)
- errors = [] of String
- skipped = [] of String
- scanned_shards = 0
- start = Time.monotonic
- Process.on_interrupt do
- print "\r"
- puts "## Finished scanning"
- puts "Scanned #{scanned_shards} shards in #{Time.monotonic - start}"
- unless skipped.empty?
- puts "Skipped shards:"
- skipped.each { |skip| puts " #{skip}" }
- puts "Found #{skipped.size} case(s) where we couldn't test Luce.to_html"
- end
- unless errors.empty?
- puts "Found issues:"
- errors.each { |error| puts " #{error}" }
- puts "Found #{errors.size} case(s) where Luce.to_html raised an error!"
- end
- abort
- end
- SHARDBOX_CATEGORIES.each do |category|
- yaml = fetch_category_yaml(category)
- next if yaml.nil?
- puts "\rTesting all shards from #{yaml["name"]}..."
- yaml["shards"].as_a.each do |shard|
- result = test_shard shard
- case result.type
- when TestResultType::Failed
- errors << result.message
- when TestResultType::Skipped
- skipped << result.message
- end
- scanned_shards += 1
- end
- sleep CATEGORY_TEST_DELAY_SECONDS
- end
- puts "## Finished scanning"
- puts "Scanned #{scanned_shards} shards in #{Time.monotonic - start}"
- unless skipped.empty?
- puts "Skipped shards:"
- skipped.each { |skip| puts " #{skip}" }
- puts "Found #{skipped.size} case(s) where we couldn't test Luce.to_html"
- end
- unless errors.empty?
- puts "Found issues:"
- errors.each { |error| puts " #{error}" }
- puts "Found #{errors.size} case(s) where Luce.to_html raised an error!"
- end
- end
- begin
- Process.run("git")
- rescue
- STDERR.puts "`git` executable not available. See https://git-scm.com"
- exit 1
- end
- main
|