Testing full git commands is helpful, but so it is to test specific functions, which is not easy to do from the shell, which is how the current testing framework is implemented. A much more modern way to test specific functions is to write a binding for a modern language--like Ruby--and then use that binding on a modern testing framework using the same language. This makes the testing framework much simpler, and also has the advantage that writing the Ruby bindings spots libification issues. Moreover no forks are needed, and crashes are handled nicely due to Ruby's exception handling. This is the best of all worlds. This step doesn't add any actual unit tests, simply prepares the groundwork for writing them. Signed-off-by: Felipe Contreras <felipe.contreras@xxxxxxxxx> --- t/Makefile | 13 +++++++++ t/ruby/git.c | 7 +++++ t/ruby/testox.rb | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ t/unit-test.t | 10 +++++++ 4 files changed, 98 insertions(+) create mode 100644 t/ruby/git.c create mode 100644 t/ruby/testox.rb create mode 100644 t/unit-test.t diff --git a/t/Makefile b/t/Makefile index d85e3e661d..4fdad529ab 100644 --- a/t/Makefile +++ b/t/Makefile @@ -47,6 +47,9 @@ CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl # scripts not to run the external "chainlint.pl" script themselves CHAINLINTSUPPRESS = GIT_TEST_EXT_CHAIN_LINT=0 && export GIT_TEST_EXT_CHAIN_LINT && +RUBY_LIBS = $(shell pkg-config --libs ruby-3.0) +RUBY_CFLAGS = $(shell pkg-config --cflags ruby-3.0) + all: $(DEFAULT_TEST_TARGET) test: pre-clean check-chainlint $(TEST_LINT) @@ -65,6 +68,13 @@ prove: pre-clean check-chainlint $(TEST_LINT) $(T): @echo "*** $@ ***"; '$(TEST_SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) +ruby/git.o: ruby/git.c + $(QUIET_CC)$(COMPILE.c) -o $@ $< + +ruby/git.so: CFLAGS := -fPIC $(RUBY_CFLAGS) -Ilib/ $(CFLAGS) +ruby/git.so: LIBS := $(RUBY_LIBS) -Llib/ -lgit $(LIBS) +ruby/git.so: ruby/git.o | lib/libgit.so + lib/git.o: lib/git.c $(QUIET_CC)$(COMPILE.c) -o $@ $< @@ -74,6 +84,9 @@ lib/libgit.so: lib/git.o %.so:: $(QUIET_LINK)$(CC) -shared -o $@ $^ $(LIBS) +test-unit: ruby/git.so + @LD_LIBRARY_PATH=lib/ ruby -Iruby unit-test.t + pre-clean: $(RM) -r '$(TEST_RESULTS_DIRECTORY_SQ)' diff --git a/t/ruby/git.c b/t/ruby/git.c new file mode 100644 index 0000000000..e75692c582 --- /dev/null +++ b/t/ruby/git.c @@ -0,0 +1,7 @@ +#include <ruby.h> +#include <git.h> + +void Init_git(void) +{ + VALUE mod = rb_define_module("Git"); +} diff --git a/t/ruby/testox.rb b/t/ruby/testox.rb new file mode 100644 index 0000000000..1cc58a3ab3 --- /dev/null +++ b/t/ruby/testox.rb @@ -0,0 +1,68 @@ +# Copyright (c) 2023 Felipe Contreras + +require 'singleton' + +class TestOxException < StandardError + attr_reader :actual, :expected + + def initialize(actual, expected) + @actual, @expected = actual, expected + end +end + +class TestOx + include Singleton + + @tests = [] + + class << self + + def add(desc, &block) + @tests << [ desc, block ] + end + + def run + success = true + + puts '1..%d' % @tests.length + + @tests.each_with_index do |(desc, block),i| + begin + instance.instance_exec(&block) + puts 'ok %d - %s' % [i + 1, desc] + rescue => e + success = false + puts 'not ok %d - %s' % [i + 1, desc] + if e.is_a?(TestOxException) + puts '# -%s' % e.expected + puts '# +%s' % e.actual + else + puts '# exception: %s' % e + end + end + end + + return success + end + + end + + def assert(string) + raise string + end + + def ok(bool) + raise TestOxException.new(bool.inspect, true) unless bool + end + + def is(actual, expected) + raise TestOxException.new(actual, expected) unless actual == expected + end + +end + +def test(*args, &block) + TestOx.add(*args, &block) +end + +at_exit { exit TestOx.run } diff --git a/t/unit-test.t b/t/unit-test.t new file mode 100644 index 0000000000..97d8a14ec3 --- /dev/null +++ b/t/unit-test.t @@ -0,0 +1,10 @@ +#!/bin/env ruby + +require 'testox' +require 'git' + +test 'basic' do + ok(true) +end + +# vim: ft=ruby -- 2.40.0+fc1