#!/usr/bin/env ruby

require "set"

Signal.trap("PIPE", "EXIT")

# See https://github.com/ruby/ruby/blob/e6ad53beaa8f61c784d7e6c9cace5bd6ecc4d5c8/test/ruby/test_file_exhaustive.rb

TEST_FILE_DIR = File.join __dir__, "..", "test", "test_files"
TEST_CODE_DIR = File.join __dir__, "..", "test"

prefixes = ["", "//", "/", ".", "/.", "bar/.", "/bar/."]
infixes = ["", " ", ".", ".ext "]
appendices = ["", " ", ".", ".bar", "::$DATA", "::$DATA.bar"]

methods = {
  basename: [],
  dirname: [],
  extname: [],
}

prefixes.each do |prefix|
  appendices.each do |appendix|
    infixes.each do |infix|

      path1 = "#{prefix}foo#{infix}#{appendix}"
      path2 = "#{prefix}foo#{infix}.ext#{appendix}"

      methods.each do |method, results|
        [path1, path2].each do |path|
          results << [path, File.send(method, path)]
        end
      end
    end
  end
end

FUNCTION = "void\ntest___rfile_%s(void)\n{\n  rstring* actual = NULL;\n  rstring* rstr = NULL;\n\n%s\n}\n\n"

File.open(File.join(TEST_CODE_DIR, "test_rfile_autogen.c"), "w") do |f|
  f.puts '/* This file was autogenerated with generate_tests.rb.  Do not edit manually. */'
  f.puts '#include <stdlib.h>'
  f.puts '#include "unity.h"'
  f.puts '#include "helper.h"'
  f.puts '#include "rlib.h"'

  f.puts

  f.puts '#define TEST_ASSERT_EQUAL_RSTRING_MESSAGE(expected, actual, msg) TEST_ASSERT_TRUE_MESSAGE(biseqcstr((const_bstring)actual, expected), msg)'

  methods.each do |method, results|
    assertions = []
    results.each do |(path, expected)|
      msg = "Path: '#{path}'"

      code = %Q[\n  actual = rfile_#{method}((rstr = rstring_new("#{path}")));\n  TEST_ASSERT_EQUAL_RSTRING_MESSAGE("#{expected}", actual, "#{msg}");\n  rstring_free(actual);\n  rstring_free(rstr);]

      assertions << code
    end

    f.puts FUNCTION % [method, assertions.join("\n")]
  end

  # Write the rfile_join tests.
  firsts  = ["", " ", "  ", ".", "..", "/", "//", "apple"]
  seconds = ["", " ", "  ", ".", "..", "/", "//", "pie"]
  thirds  = ["", " ", "  ", ".", "..", "/", "//", "good"]

  join_fn = "
void
test___rfile_join(void)
{
  rstring* actual = NULL;
  rstring_array* rary = NULL;

%s
}
"
  n = 0
  assertions = []
  firsts.each do |first|
    seconds.each do |second|
      thirds.each do |third|
        n += 1

        strings = %Q~
  rary = rstring_array_new();
  rstring_array_push_cstr(rary, "%s");
  rstring_array_push_cstr(rary, "%s");
  rstring_array_push_cstr(rary, "%s");
~ % [first, second, third]

        # strings = %Q~  rstring* strings%s[3] = { rstring_new("%s"), rstring_new("%s"), rstring_new("%s") };~ % [n, first, second, third]

        # Ruby has some weird behavior here where it sometimes keeps
        # double // and sometimes it doesn't.  It doesn't in cases
        # where there is more than one slash in a single one of the
        # input strings.  Regardless, the function is for building
        # paths so in that spirit, we don't want those double
        # separators anyways.
        expected = File.join(first, second, third).gsub(/\/+/, "/")

        msg = "Path%s: ['%s', '%s', '%s']" % [n, first, second, third]

        test = %Q~  TEST_ASSERT_EQUAL_RSTRING_MESSAGE("%s", (actual = rfile_join(rary)), "%s");~ % [expected, n, msg]
        clean_up = %Q~  rstring_free(actual); rstring_array_free(rary);~

        assertions << ("%s\n%s\n%s" % [strings, test, clean_up])
      end
    end
  end

  f.puts join_fn % assertions.join("\n\n")
end
