diff mbox series

[RFC,2/3] test: add basic unit testing framework

Message ID 20230502041113.103385-3-felipe.contreras@gmail.com (mailing list archive)
State New, archived
Headers show
Series test: new testing framework for libification | expand

Commit Message

Felipe Contreras May 2, 2023, 4:11 a.m. UTC
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@gmail.com>
---
 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 mbox series

Patch

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