std::string throws typemaps

Go, Guile, Racket, Scilab: Add throws typemaps for std::string so that
thrown string exception messages can be seen.

Test all language for std::string throws typemaps
This commit is contained in:
William S Fulton 2022-09-18 20:20:21 +01:00
commit ed333b6b97
24 changed files with 225 additions and 12 deletions

View file

@ -7,6 +7,14 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.1.0 (in progress) Version 4.1.0 (in progress)
=========================== ===========================
2022-09-17: wsfulton
[Go, Guile, Racket, Scilab] Add throws typemaps for std::string so that thrown
string exception messages can be seen.
2022-09-17: wsfulton
[Racket] Add throws typemaps for char * so that thrown string exception
messages can be seen from Racket.
2022-09-17: wsfulton 2022-09-17: wsfulton
[Javascript, Octave, R] Improve exceptions for %catches and exception [Javascript, Octave, R] Improve exceptions for %catches and exception
specifications for native types. String exception messages are shown as specifications for native types. String exception messages are shown as

View file

@ -3,11 +3,15 @@
%include <std_string.i> %include <std_string.i>
%catches(const char *) StringsThrower::charstring; %catches(const char *) StringsThrower::charstring;
%catches(std::string) StringsThrower::stdstring;
%inline %{ %inline %{
struct StringsThrower { struct StringsThrower {
static void charstring() { static void charstring() {
throw "charstring message"; throw "charstring message";
} }
static void stdstring() {
throw std::string("stdstring message");
}
}; };
%} %}

View file

@ -16,5 +16,17 @@ public class catches_strings_runme {
if (!exception_thrown) if (!exception_thrown)
throw new ApplicationException("Should have thrown an exception"); throw new ApplicationException("Should have thrown an exception");
} }
{
bool exception_thrown = false;
try {
StringsThrower.stdstring();
} catch (ApplicationException e) {
if (!e.Message.Contains("stdstring message"))
throw new ApplicationException("incorrect exception message:" + e);
exception_thrown = true;
}
if (!exception_thrown)
throw new ApplicationException("Should have thrown an exception");
}
} }
} }

View file

@ -17,4 +17,16 @@ void main() {
if (!exception_thrown) if (!exception_thrown)
throw new Exception("Should have thrown an exception"); throw new Exception("Should have thrown an exception");
} }
{
bool exception_thrown = false;
try {
StringsThrower.stdstring();
} catch (Exception e) {
if (!canFind(e.msg, "stdstring message"))
throw new Exception("incorrect exception message:" ~ e.msg);
exception_thrown = true;
}
if (!exception_thrown)
throw new Exception("Should have thrown an exception");
}
} }

View file

@ -17,4 +17,16 @@ void main() {
if (!exception_thrown) if (!exception_thrown)
throw new Exception("Should have thrown an exception"); throw new Exception("Should have thrown an exception");
} }
{
bool exception_thrown = false;
try {
StringsThrower.stdstring();
} catch (Exception e) {
if (!canFind(e.msg, "stdstring message"))
throw new Exception("incorrect exception message:" ~ e.msg);
exception_thrown = true;
}
if (!exception_thrown)
throw new Exception("Should have thrown an exception");
}
} }

View file

@ -4,6 +4,7 @@ import "strings"
import . "swigtests/catches_strings" import . "swigtests/catches_strings"
func main() { func main() {
{
exception_thrown := false exception_thrown := false
func() { func() {
defer func() { defer func() {
@ -15,3 +16,17 @@ func main() {
panic(0) panic(0)
} }
} }
{
exception_thrown := false
func() {
defer func() {
exception_thrown = strings.Index(recover().(string), "stdstring message") == 0
}()
StringsThrowerStdstring()
}()
if !exception_thrown {
panic(0)
}
}
}

View file

@ -24,5 +24,18 @@ public class catches_strings_runme {
if (!exception_thrown) if (!exception_thrown)
throw new RuntimeException("Should have thrown an exception"); throw new RuntimeException("Should have thrown an exception");
} }
{
boolean exception_thrown = false;
try {
StringsThrower.stdstring();
} catch (RuntimeException e) {
if (!e.getMessage().contains("stdstring message"))
throw new RuntimeException("incorrect exception message");
exception_thrown = true;
}
if (!exception_thrown)
throw new RuntimeException("Should have thrown an exception");
}
} }
} }

View file

@ -4,12 +4,20 @@ exception_thrown = false;
try { try {
catches_strings.StringsThrower.charstring(); catches_strings.StringsThrower.charstring();
} catch (e) { } catch (e) {
console.log(typeof(e))
console.log(e.constructor.name)
console.log(typeof(e.message))
if (!e.message.includes("charstring message")) if (!e.message.includes("charstring message"))
throw new Error("incorrect exception message " + e.message); throw new Error("incorrect exception message " + e.message);
exception_thrown = true; exception_thrown = true;
} }
if (!exception_thrown) if (!exception_thrown)
throw new Error("Should have thrown an exception"); throw new Error("Should have thrown an exception");
exception_thrown = false;
try {
catches_strings.StringsThrower.stdstring();
} catch (e) {
if (!e.message.includes("stdstring message"))
throw new Error("incorrect exception message " + e.message);
exception_thrown = true;
}
if (!exception_thrown)
throw new Error("Should have thrown an exception");

View file

@ -8,3 +8,6 @@ setmetatable(env, {__index=function (t,i) error("undefined global variable `"..i
s, msg = pcall(function() catches_strings.StringsThrower.charstring() end) s, msg = pcall(function() catches_strings.StringsThrower.charstring() end)
assert(s == false and msg:find("charstring message", 1, true)) assert(s == false and msg:find("charstring message", 1, true))
s, msg = pcall(function() catches_strings.StringsThrower.stdstring() end)
assert(s == false and msg:find("stdstring message", 1, true))

View file

@ -8,4 +8,11 @@
(unless (string-contains? exception_thrown "charstring message") (unless (string-contains? exception_thrown "charstring message")
(error (format "incorrect exception message: ~a" exception_thrown))) (error (format "incorrect exception message: ~a" exception_thrown)))
(define exception_thrown "no exception thrown for kin")
(with-handlers ([exn:fail? (lambda (exn)
(set! exception_thrown (exn-message exn)))])
(StringsThrower-stdstring))
(unless (string-contains? exception_thrown "stdstring message")
(error (format "incorrect exception message: ~a" exception_thrown)))
(exit 0) (exit 0)

View file

@ -6,3 +6,9 @@ let _ =
ignore (_StringsThrower_charstring (C_void)); assert false ignore (_StringsThrower_charstring (C_void)); assert false
with Failure s -> with Failure s ->
assert (s = "charstring message") assert (s = "charstring message")
let _ =
try
ignore (_StringsThrower_stdstring (C_void)); assert false
with Failure s ->
assert (s = "stdstring message")

View file

@ -17,3 +17,16 @@ end_try_catch
if (!exception_thrown) if (!exception_thrown)
error("Should have thrown an exception"); error("Should have thrown an exception");
endif endif
exception_thrown = false;
try
StringsThrower.stdstring();
catch e
if (isempty(strfind(e.message, "stdstring message")))
error("incorrect exception message: %s", e.message)
endif
exception_thrown = true;
end_try_catch
if (!exception_thrown)
error("Should have thrown an exception");
endif

View file

@ -1,6 +1,6 @@
use strict; use strict;
use warnings; use warnings;
use Test::More tests => 3; use Test::More tests => 4;
BEGIN { use_ok('catches_strings') } BEGIN { use_ok('catches_strings') }
require_ok('catches_strings'); require_ok('catches_strings');
@ -8,3 +8,8 @@ eval {
catches_strings::StringsThrower::charstring(); catches_strings::StringsThrower::charstring();
}; };
like($@, qr/\bcharstring message/, "Should have thrown an exception"); like($@, qr/\bcharstring message/, "Should have thrown an exception");
eval {
catches_strings::StringsThrower::stdstring();
};
like($@, qr/\bstdstring message/, "Should have thrown an exception");

View file

@ -11,4 +11,13 @@ try {
} }
check::equal($exception_thrown, true, "Should have thrown an exception"); check::equal($exception_thrown, true, "Should have thrown an exception");
$exception_thrown = false;
try {
StringsThrower::stdstring();
} catch (Exception $e) {
check::str_contains($e->getMessage(), "stdstring message", "incorrect exception message: {$e->getMessage()}");
$exception_thrown = true;
}
check::equal($exception_thrown, true, "Should have thrown an exception");
check::done(); check::done();

View file

@ -9,3 +9,13 @@ except RuntimeError as e:
exception_thrown = True exception_thrown = True
if not exception_thrown: if not exception_thrown:
raise RuntimeError("Should have thrown an exception") raise RuntimeError("Should have thrown an exception")
exception_thrown = False
try:
StringsThrower.stdstring()
except RuntimeError as e:
if "stdstring message" not in str(e):
raise RuntimeError("incorrect exception message:" + str(e))
exception_thrown = True
if not exception_thrown:
raise RuntimeError("Should have thrown an exception")

View file

@ -13,3 +13,12 @@ tryCatch({
} }
) )
unittest(exception_thrown, TRUE) unittest(exception_thrown, TRUE)
exception_thrown = FALSE
tryCatch({
StringsThrower_stdstring()
}, error = function(e) {
exception_thrown <<- grepl(e$message, "stdstring message", fixed=TRUE)
}
)
unittest(exception_thrown, TRUE)

View file

@ -16,3 +16,16 @@ end
if (!exception_thrown) if (!exception_thrown)
raise RuntimeError, "Should have thrown an exception" raise RuntimeError, "Should have thrown an exception"
end end
exception_thrown = false
begin
Catches_strings::StringsThrower.stdstring()
rescue RuntimeError => e
if (!e.to_s.include? "stdstring message")
raise RuntimeError, "incorrect exception message: #{e.to_s}"
end
exception_thrown = true
end
if (!exception_thrown)
raise RuntimeError, "Should have thrown an exception"
end

View file

@ -2,4 +2,8 @@
(StringsThrower-charstring)) (StringsThrower-charstring))
; TODO: check the exception message ; TODO: check the exception message
(expect-throw 'swig-exception
(StringsThrower-stdstring))
; TODO: check the exception message
(exit 0) (exit 0)

View file

@ -7,4 +7,11 @@ if (strstr(lasterror(), "charstring message") == '')
exit(1) exit(1)
end end
ierr = execstr("StringsThrower_stdstring()", 'errcatch');
checkequal(ierr, 20000, "wrong/no exception thrown")
if (strstr(lasterror(), "stdstring message") == '')
printf("Should have thrown an exception")
exit(1)
end
exec("swigtest.quit", -1); exec("swigtest.quit", -1);

View file

@ -16,3 +16,16 @@ if [ catch {
if {!$exception_thrown} { if {!$exception_thrown} {
error "Should have thrown an exception" error "Should have thrown an exception"
} }
set exception_thrown 0
if [ catch {
StringsThrower_stdstring
} e ] {
if {[string first "stdstring message" $e] == -1} {
error "incorrect exception message: $e"
}
set exception_thrown 1
}
if {!$exception_thrown} {
error "Should have thrown an exception"
}

View file

@ -52,6 +52,9 @@ class string;
%typemap(godirectorin,fragment="CopyString") string %typemap(godirectorin,fragment="CopyString") string
%{ $result = swigCopyString($input) %} %{ $result = swigCopyString($input) %}
%typemap(throws) string
%{ _swig_gopanic($1.c_str()); %}
%typemap(in) const string & %typemap(in) const string &
%{ %{
$*1_ltype $1_str($input.p, $input.n); $*1_ltype $1_str($input.p, $input.n);
@ -88,6 +91,9 @@ class string;
%typemap(godirectorin,fragment="CopyString") const string & %typemap(godirectorin,fragment="CopyString") const string &
%{ $result = swigCopyString($input) %} %{ $result = swigCopyString($input) %}
%typemap(throws) const string &
%{ _swig_gopanic($1.c_str()); %}
%typemap(gotype) string * "*string" %typemap(gotype) string * "*string"

View file

@ -83,4 +83,13 @@ namespace std {
$result = SWIG_str02scm($1.c_str()); $result = SWIG_str02scm($1.c_str());
} }
%typemap(throws) string {
scm_throw(scm_from_locale_symbol((char *) "swig-exception"),
scm_list_n(SWIG_str02scm($1.c_str()), SCM_UNDEFINED));
}
%typemap(throws) const string & {
scm_throw(scm_from_locale_symbol((char *) "swig-exception"),
scm_list_n(SWIG_str02scm($1.c_str()), SCM_UNDEFINED));
}
} }

View file

@ -52,6 +52,13 @@ namespace std {
$result = scheme_make_string($1->c_str()); $result = scheme_make_string($1->c_str());
} }
%typemap(throws) string {
scheme_signal_error("%s: %s", FUNC_NAME, $1.c_str());
}
%typemap(throws) const string & {
scheme_signal_error("%s: %s", FUNC_NAME, $1.c_str());
}
} }

View file

@ -37,3 +37,11 @@ SWIG_From_dec(std::string)(std::string pstValue) {
} }
%include <typemaps/std_string.swg> %include <typemaps/std_string.swg>
%typemap(throws, noblock=1) std::string {
SWIG_Scilab_Raise_Ex($1.c_str(), "$type", $&descriptor);
}
%typemap(throws, noblock=1) const std::string & {
SWIG_Scilab_Raise_Ex($1.c_str(), "$type", $descriptor);
}