# frozen_string_literal: true require 'minitest/autorun' require 'open3' require 'tmpdir' require 'fileutils' # Runs the examples from the printed handbook (demo/handbuch/beispiele.txt) and # compares each output with the one printed in the book. Whitespace does not # count: the book aligns columns with spaces, we write tabs. class HandbuchTest < Minitest::Test ROOT = File.expand_path('..', __dir__) DIR = File.join(ROOT, 'demo', 'handbuch') Example = Struct.new(:dir, :title, :cmd, :expected, :deviation) def self.examples list = [] dir = '.' title = nil deviation = nil cur = nil lines = File.readlines(File.join(DIR, 'beispiele.txt'), chomp: true) until lines.empty? line = lines.shift if line.start_with?('$ ') cmd = line[2..] cmd += "\n" + lines.shift while cmd.match?(/[|\\]\s*\z/) && lines.any? cur = Example.new(dir, title, cmd, [], deviation) list << cur elsif line.start_with?('@ ') dir = line[2..].strip cur = nil elsif line.start_with?('## ') title = line[3..] deviation = nil cur = nil elsif line.start_with?('! ') deviation = line[2..] elsif line.start_with?('#') next elsif cur cur.expected << line end end list end # Cells without whitespace; dash runs count as one dash; blank lines drop out. def self.normalize(lines) lines.map { |l| l.split.map { |w| w.match?(/\A-+\z/) ? '-' : w }.join(' ') }.reject(&:empty?) end def run_example(ex, scratch) env = { 'PATH' => "#{File.join(ROOT, 'bin')}:#{ENV['PATH']}" } out, _st = Open3.capture2e(env, 'sh', '-c', ex.cmd, chdir: File.join(scratch, ex.dir), stdin_data: '') out.lines(chomp: true) end def test_examples_from_the_book failures = [] fixed = [] Dir.mktmpdir('rdb-handbuch') do |scratch| FileUtils.cp_r(Dir[File.join(DIR, '*')], scratch) self.class.examples.each do |ex| got = self.class.normalize(run_example(ex, scratch)) next if ex.expected.empty? want = self.class.normalize(ex.expected) if ex.deviation fixed << "#{ex.title}: stimmt jetzt mit dem Buch überein, '!' entfernen" if got == want elsif got != want failures << "#{ex.title}\n $ #{ex.cmd}\n Buch: #{want.inspect}\n erhalten: #{got.inspect}" end end end assert_empty failures + fixed, (failures + fixed).join("\n\n") end end