[ruby-oci8-commit] [254] trunk/ruby-oci8: * ext/oci8/.: add apiwrap.[ch] to svn: ignore property.
nobody at rubyforge.org
nobody at rubyforge.org
Fri Mar 21 23:18:42 EDT 2008
Revision: 254
Author: kubo
Date: 2008-03-21 23:18:42 -0400 (Fri, 21 Mar 2008)
Log Message:
-----------
* ext/oci8/.: add apiwrap.[ch] to svn:ignore property.
* ext/oci8/apiwrap.c.tmpl, ext/oci8/apiwrap.rb, ext/oci8/apiwrap.yml:
add alternative code if OCINumberSetPi(), OCINumberIsInt() is
not found.
* ext/oci8/oci8.h: delete unused macros. add LIKELY and UNLIKELY
macros and use the former in oci8_get_errhp().
* ext/oci8/oci8.h, ext/oci8/oci8lib.c: change the scope of
oci8_base_class to static.
* ext/oci8/ocinumber.c: fix OraNumber#** and OraNumber#<=>. raise
exceptions when OraNumber#round_prec or OraNumber#shift is called
and the Oracle client version is 8.0.
* test/test_oranumber.rb: add testcass for all OraNumber methods.
Modified Paths:
--------------
trunk/ruby-oci8/ChangeLog
trunk/ruby-oci8/ext/oci8/apiwrap.c.tmpl
trunk/ruby-oci8/ext/oci8/apiwrap.rb
trunk/ruby-oci8/ext/oci8/apiwrap.yml
trunk/ruby-oci8/ext/oci8/oci8.h
trunk/ruby-oci8/ext/oci8/oci8lib.c
trunk/ruby-oci8/ext/oci8/ocinumber.c
trunk/ruby-oci8/test/test_oranumber.rb
Property Changed:
----------------
trunk/ruby-oci8/ext/oci8/
Modified: trunk/ruby-oci8/ChangeLog
===================================================================
--- trunk/ruby-oci8/ChangeLog 2008-03-19 14:02:00 UTC (rev 253)
+++ trunk/ruby-oci8/ChangeLog 2008-03-22 03:18:42 UTC (rev 254)
@@ -1,3 +1,17 @@
+2008-03-22 KUBO Takehiro <kubo at jiubao.org>
+ * ext/oci8/.: add apiwrap.[ch] to svn:ignore property.
+ * ext/oci8/apiwrap.c.tmpl, ext/oci8/apiwrap.rb, ext/oci8/apiwrap.yml:
+ add alternative code if OCINumberSetPi(), OCINumberIsInt() is
+ not found.
+ * ext/oci8/oci8.h: delete unused macros. add LIKELY and UNLIKELY
+ macros and use the former in oci8_get_errhp().
+ * ext/oci8/oci8.h, ext/oci8/oci8lib.c: change the scope of
+ oci8_base_class to static.
+ * ext/oci8/ocinumber.c: fix OraNumber#** and OraNumber#<=>. raise
+ exceptions when OraNumber#round_prec or OraNumber#shift is called
+ and the Oracle client version is 8.0.
+ * test/test_oranumber.rb: add testcass for all OraNumber methods.
+
2008-03-19 KUBO Takehiro <kubo at jiubao.org>
* ext/oci8/ocinumber.c, lib/oci8/compat.rb, lib/oci8/object.rb
lib/oci8/oci8.rb, test/test_oci8.rb:
Property changes on: trunk/ruby-oci8/ext/oci8
___________________________________________________________________
Name: svn:ignore
- Makefile
mkmf.log
extconf.h
depend
oci8lib.so
+ Makefile
mkmf.log
extconf.h
depend
oci8lib.so
apiwrap.c
apiwrap.h
Modified: trunk/ruby-oci8/ext/oci8/apiwrap.c.tmpl
===================================================================
--- trunk/ruby-oci8/ext/oci8/apiwrap.c.tmpl 2008-03-19 14:02:00 UTC (rev 253)
+++ trunk/ruby-oci8/ext/oci8/apiwrap.c.tmpl 2008-03-22 03:18:42 UTC (rev 254)
@@ -109,8 +109,11 @@
%> return <%=f.name%>(<%=f.args.collect {|arg| arg.name}.join(', ')%>);
<% end
%> } else {
- rb_raise(rb_eRuntimeError, "undefined OCI function %s is called", "<%=f.name%>");
- }
+<% if f.code_if_not_found %><%=f.code_if_not_found.split("\n").collect {|line| " " + line}.join("\n")%>
+<% else
+%> rb_raise(rb_eRuntimeError, "undefined OCI function %s is called", "<%=f.name%>");
+<% end
+%> }
}
<%
######################################################################
Modified: trunk/ruby-oci8/ext/oci8/apiwrap.rb
===================================================================
--- trunk/ruby-oci8/ext/oci8/apiwrap.rb 2008-03-19 14:02:00 UTC (rev 253)
+++ trunk/ruby-oci8/ext/oci8/apiwrap.rb 2008-03-22 03:18:42 UTC (rev 254)
@@ -19,6 +19,7 @@
attr_reader :remote
attr_reader :args
attr_reader :ret
+ attr_reader :code_if_not_found
def initialize(key, val)
if key[-3..-1] == '_nb'
@@ -33,6 +34,7 @@
@args = val[:args].collect do |arg|
ArgDef.new(arg)
end
+ @code_if_not_found = val[:code_if_not_found]
end
end
Modified: trunk/ruby-oci8/ext/oci8/apiwrap.yml
===================================================================
--- trunk/ruby-oci8/ext/oci8/apiwrap.yml 2008-03-19 14:02:00 UTC (rev 253)
+++ trunk/ruby-oci8/ext/oci8/apiwrap.yml 2008-03-22 03:18:42 UTC (rev 254)
@@ -939,6 +939,26 @@
:args: - OCIError *err
- const OCINumber *number
- boolean *result
+ :code_if_not_found: |
+ /* pseude code
+ * work = trunc(number);
+ * if (number == work) {
+ * result = TRUE;
+ * } else {
+ * result = FALSE;
+ * }
+ */
+ OCINumber work;
+ sword rv;
+ sword cmp;
+ rv = oci8_OCINumberTrunc(err, number, 0, &work, file, line);
+ if (rv != OCI_SUCCESS)
+ return rv;
+ rv = oci8_OCINumberCmp(err, number, &work, &cmp, file, line);
+ if (rv != OCI_SUCCESS)
+ return rv;
+ *result = (cmp == 0) ? TRUE : FALSE;
+ return OCI_SUCCESS;
# round trip: 0
OCINumberPrec:
@@ -954,6 +974,13 @@
:ret: void
:args: - OCIError *err
- OCINumber *num
+ :code_if_not_found: |
+ static const OCINumber pi = {
+ {0x15, 0xc1, 0x04, 0x0f, 0x10, 0x5d, 0x42, 0x24, 0x5a, 0x50,
+ 0x21, 0x27, 0x2f, 0x1b, 0x2c, 0x27, 0x21, 0x50, 0x33, 0x1d,
+ 0x55, 0x15}
+ };
+ *num = pi;
# round trip: 0
OCINumberShift:
Modified: trunk/ruby-oci8/ext/oci8/oci8.h
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8.h 2008-03-19 14:02:00 UTC (rev 253)
+++ trunk/ruby-oci8/ext/oci8/oci8.h 2008-03-22 03:18:42 UTC (rev 254)
@@ -69,6 +69,17 @@
#define IS_OCI_ERROR(v) (((v) != OCI_SUCCESS) && ((v) != OCI_SUCCESS_WITH_INFO))
+#if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
+/* LIKELY tells the compiler that x is 1(TRUE) in many cases.
+ * This may optimize branch prediction in the assembler code.
+ */
+#define LIKELY(x) (__builtin_expect((x), 1))
+#define UNLIKELY(x) (__builtin_expect((x), 0))
+#else
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#endif
+
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
/* gcc version >= 3.1 */
#define ALWAYS_INLINE inline __attribute__((always_inline))
@@ -215,11 +226,6 @@
#define UB4_TO_NUM UINT2NUM
#endif
-/* dangerous macros */
-#define CHECK_STRING(obj) if (!NIL_P(obj)) { StringValue(obj); }
-#define TO_STRING_PTR(obj) (NIL_P(obj) ? NULL : RSTRING(obj)->ptr)
-#define TO_STRING_LEN(obj) (NIL_P(obj) ? 0 : RSTRING(obj)->len)
-
/* env.c */
extern OCIEnv *oci8_envhp;
#ifdef RUBY_VM
@@ -250,7 +256,7 @@
static inline OCIError *oci8_get_errhp()
{
OCIError *errhp = (OCIError *)oci8_tls_get(oci8_tls_key);
- return (errhp != NULL) ? errhp : oci8_make_errhp();
+ return LIKELY(errhp != NULL) ? errhp : oci8_make_errhp();
}
#else
@@ -279,7 +285,6 @@
#if defined RUNTIME_API_CHECK
void *oci8_find_symbol(const char *symbol_name);
#endif
-extern oci8_base_class_t oci8_base_class;
/* error.c */
extern VALUE eOCIException;
Modified: trunk/ruby-oci8/ext/oci8/oci8lib.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/oci8lib.c 2008-03-19 14:02:00 UTC (rev 253)
+++ trunk/ruby-oci8/ext/oci8/oci8lib.c 2008-03-22 03:18:42 UTC (rev 254)
@@ -1,6 +1,6 @@
/* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
/*
- * Copyright (C) 2002-2007 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2002-2008 KUBO Takehiro <kubo at jiubao.org>
*/
#ifdef __linux__ /* for RTLD_DEFAULT */
@@ -15,7 +15,7 @@
#include <signal.h>
#endif
-oci8_base_class_t oci8_base_class = {
+static oci8_base_class_t oci8_base_class = {
NULL,
NULL,
sizeof(oci8_base_t),
Modified: trunk/ruby-oci8/ext/oci8/ocinumber.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/ocinumber.c 2008-03-19 14:02:00 UTC (rev 253)
+++ trunk/ruby-oci8/ext/oci8/ocinumber.c 2008-03-22 03:18:42 UTC (rev 254)
@@ -5,7 +5,7 @@
* $Author$
* $Date$
*
- * Copyright (C) 2005-2007 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2005-2008 KUBO Takehiro <kubo at jiubao.org>
*
*/
#include "oci8.h"
@@ -655,8 +655,6 @@
{
OCINumber n;
OCINumber r;
- sword sign;
- boolean is_int;
if (FIXNUM_P(rhs)) {
oci_lc(OCINumberIntPower(oci8_errhp, _NUMBER(lhs), FIX2INT(rhs), &r));
@@ -664,12 +662,6 @@
/* change to OCINumber */
if (!set_oci_number_from_num(&n, rhs, 0))
return rb_num_coerce_bin(lhs, rhs, id_power);
- /* check whether num1 is negative. */
- oci_lc(OCINumberSign(oci8_errhp, _NUMBER(lhs), &sign));
- /* check whether num2 is an integral value. */
- oci_lc(OCINumberIsInt(oci8_errhp, &n, &is_int));
- if (sign < 0 && !is_int)
- rb_raise(rb_eRangeError, "base is negative and exponent part is not an integral value");
oci_lc(OCINumberPower(oci8_errhp, _NUMBER(lhs), &n, &r));
}
return oci8_make_ocinumber(&r);
@@ -693,7 +685,13 @@
return rb_num_coerce_cmp(lhs, rhs, id_cmp);
/* compare */
oci_lc(OCINumberCmp(oci8_errhp, _NUMBER(lhs), &n, &r));
- return INT2NUM(r);
+ if (r > 0) {
+ return INT2FIX(1);
+ } else if (r == 0) {
+ return INT2FIX(0);
+ } else {
+ return INT2FIX(-1);
+ }
}
/*
@@ -732,6 +730,10 @@
*
* Rounds <i>onum</i> to the nearest <code>Integer</code> when no argument.
* Rounds <i>onum</i> to a specified decimal place <i>decplace</i> when one argument.
+ *
+ * OraNumber.new(1.234).round(1) #=> 1.2
+ * OraNumber.new(1.234).round(2) #=> 1.23
+ * OraNumber.new(1.234).round(3) #=> 1.234
*/
static VALUE onum_round(int argc, VALUE *argv, VALUE self)
{
@@ -770,6 +772,7 @@
* onum.round_prec(digits) -> oranumber
*
* Rounds <i>onum</i> to a specified number of decimal digits.
+ * This method is available on Oracle 8.1 client or upper.
*
* OraNumber.new(1.234).round_prec(2) #=> 1.2
* OraNumber.new(12.34).round_prec(2) #=> 12
@@ -779,6 +782,10 @@
{
OCINumber r;
+ if (!have_OCINumberPrec) {
+ rb_raise(rb_eNotImpError, "The Oracle client version is too lower to use %s#round_prec",
+ rb_obj_classname(self));
+ }
oci_lc(OCINumberPrec(oci8_errhp, _NUMBER(self), NUM2INT(ndigs), &r));
return oci8_make_ocinumber(&r);
}
@@ -938,11 +945,16 @@
* onum.shift(fixnum) -> oranumber
*
* Returns <i>onum</i> * 10**<i>fixnum</i>
+ * This method is available on Oracle 8.1 client or upper.
*/
static VALUE onum_shift(VALUE self, VALUE exp)
{
OCINumber result;
+ if (!have_OCINumberShift) {
+ rb_raise(rb_eNotImpError, "The Oracle client version is too lower to use %s#shift",
+ rb_obj_classname(self));
+ }
oci_lc(OCINumberShift(oci8_errhp, _NUMBER(self), NUM2INT(exp), &result));
return oci8_make_ocinumber(&result);
}
Modified: trunk/ruby-oci8/test/test_oranumber.rb
===================================================================
--- trunk/ruby-oci8/test/test_oranumber.rb 2008-03-19 14:02:00 UTC (rev 253)
+++ trunk/ruby-oci8/test/test_oranumber.rb 2008-03-22 03:18:42 UTC (rev 254)
@@ -2,10 +2,11 @@
require 'oci8'
require 'test/unit'
require './config'
+require 'yaml'
class TestOraNumber < Test::Unit::TestCase
- NUMBER_CHECK_TARGET = [
+ LARGE_RANGE_VALUES = [
"12345678901234567890123456789012345678",
"1234567890123456789012345678901234567",
"1234567890123456789012345678901234567.8",
@@ -52,91 +53,425 @@
"-1.123",
]
- def setup
- @conn = get_oci8_connection
- end
+ SMALL_RANGE_VALUES = [
+ "10",
+ "3",
+ "3.14159265358979323846", # PI
+ "2",
+ "1.57079632679489661923", # PI/2
+ "0.5",
+ "0.0000000001",
+ "0",
+ "-0.0000000001",
+ "-0.5",
+ "-1.57079632679489661923", # -PI/2
+ "-2",
+ "-3.14159265358979323846", # -PI
+ "-3",
+ "-10",
+ ]
- def test_to_s
- cursor = @conn.parse("BEGIN :number := TO_NUMBER(:str); END;")
- cursor.bind_param(:number, OraNumber)
- cursor.bind_param(:str, nil, String, 40)
- NUMBER_CHECK_TARGET.each do |val|
- cursor[:str] = val
- cursor.exec
- assert_equal(val, cursor[:number].to_s)
+ def compare_with_float(values, rettype, proc1, proc2 = nil)
+ proc2 = proc1 if proc2.nil?
+ values.each do |x|
+ expected_val = proc1.call(x.to_f)
+ actual_val = proc2.call(OraNumber.new(x))
+ assert_kind_of(rettype, actual_val)
+ delta = [expected_val.abs * 1.0e-12, 1.0e-14].max
+ assert_in_delta(expected_val, actual_val, delta, x)
end
end
- def test_to_i
- cursor = @conn.parse("BEGIN :number := TO_NUMBER(:str); END;")
- cursor.bind_param(:number, OraNumber)
- cursor.bind_param(:str, nil, String, 40)
- NUMBER_CHECK_TARGET.each do |val|
- cursor[:str] = val
- cursor.exec
- assert_equal(val.to_i, cursor[:number].to_i)
+ def compare_with_float2(values, proc_args, proc1, proc2 = nil)
+ proc2 = proc1 if proc2.nil?
+ values.each do |x|
+ proc_args.each do |y|
+ expected_val = proc1.call(x.to_f, y)
+ actual_val = proc2.call(OraNumber.new(x), y)
+ begin
+ delta = [expected_val.abs * 1.0e-12, 1.0e-14].max
+ rescue
+ puts '-----------'
+ p x
+ p y
+ p expected_val
+ puts '-----------'
+ raise $!
+ end
+ assert_in_delta(expected_val, actual_val, delta, x)
+ end
end
end
- def test_to_f
- cursor = @conn.parse("BEGIN :number := TO_NUMBER(:str); END;")
- cursor.bind_param(:number, OraNumber)
- cursor.bind_param(:str, nil, String, 40)
- NUMBER_CHECK_TARGET.each do |val|
- cursor[:str] = val
- cursor.exec
- assert_in_delta(val.to_f, cursor[:number].to_f, val.to_f.abs * 1e-14)
+ def test_in_bind
+ conn = get_oci8_connection
+ begin
+ conn.exec("alter session set nls_numeric_characters = '.,'")
+ cursor = conn.parse("BEGIN :out := TO_CHAR(:in); END;")
+ cursor.bind_param(:out, nil, String, 40)
+ cursor.bind_param(:in, OraNumber)
+ LARGE_RANGE_VALUES.each do |val|
+ cursor[:in] = OraNumber.new(val)
+ cursor.exec
+ # convert 0.0001 and -0.0001 to .0001 and -.0001 respectively
+ val = $1+'.'+$2 if /(-?)0\.(.*)/ =~ val
+ assert_equal(val, cursor[:out])
+ end
+ ensure
+ conn.logoff
end
end
- def test_uminus
- cursor = @conn.parse("BEGIN :number := - TO_NUMBER(:str); END;")
- cursor.bind_param(:number, OraNumber)
- cursor.bind_param(:str, nil, String, 40)
- NUMBER_CHECK_TARGET.each do |val|
- cursor[:str] = val
- cursor.exec
- assert_equal(val, (- (cursor[:number])).to_s)
+ def test_out_bind
+ conn = get_oci8_connection
+ begin
+ conn.exec("alter session set nls_numeric_characters = '.,'")
+ cursor = conn.parse("BEGIN :out := TO_NUMBER(:in); END;")
+ cursor.bind_param(:out, OraNumber)
+ cursor.bind_param(:in, nil, String, 40)
+ LARGE_RANGE_VALUES.each do |val|
+ cursor[:in] = val
+ cursor.exec
+ assert_equal(OraNumber.new(val), cursor[:out])
+ end
+ ensure
+ conn.logoff
end
end
def test_dup
- cursor = @conn.parse("BEGIN :number := TO_NUMBER(:str); END;")
- cursor.bind_param(:number, OraNumber)
- cursor.bind_param(:str, nil, String, 40)
- NUMBER_CHECK_TARGET.each do |val|
- cursor[:str] = val
- cursor.exec
- n = cursor[:number]
- assert_equal(n.to_s, n.dup.to_s)
- assert_equal(n.to_s, n.clone.to_s)
+ LARGE_RANGE_VALUES.each do |x|
+ n = OraNumber.new(x)
+ assert_equal(n, n.dup)
+ assert_equal(n, n.clone)
end
end
def test_marshal
- cursor = @conn.parse("BEGIN :number := TO_NUMBER(:str); END;")
- cursor.bind_param(:number, OraNumber)
- cursor.bind_param(:str, nil, String, 40)
- NUMBER_CHECK_TARGET.each do |val|
- cursor[:str] = val
- cursor.exec
- n = cursor[:number]
- assert_equal(n.to_s, Marshal.load(Marshal.dump(n)).to_s)
+ LARGE_RANGE_VALUES.each do |x|
+ n = OraNumber.new(x)
+ assert_equal(n, Marshal.load(Marshal.dump(n)))
end
end
- def test_new_from_string
- cursor = @conn.parse("BEGIN :number := TO_NUMBER(:str); END;")
- cursor.bind_param(:number, OraNumber)
- cursor.bind_param(:str, nil, String, 40)
- (NUMBER_CHECK_TARGET + ["1.230", "1.2300", "1.23000"]).each do |val|
- cursor[:str] = val
- cursor.exec
- assert_equal(cursor[:number].to_s, OraNumber.new(val).to_s)
+ def test_yaml
+ LARGE_RANGE_VALUES.each do |x|
+ n = OraNumber.new(x)
+ assert_equal(n, YAML.load(YAML.dump(n)))
end
end
- def teardown
- @conn.logoff
+ # OCI8::Math.acos(x) -> ocinumber
+ def test_math_acos
+ test_values = []
+ -1.0.step(1.0, 0.01) do |n|
+ test_values << n
+ end
+ compare_with_float(test_values, OraNumber,
+ Proc.new {|n| Math::acos(n)},
+ Proc.new {|n| OCI8::Math::acos(n)})
end
+
+ # OCI8::Math.asin(x) -> ocinumber
+ def test_math_asin
+ test_values = []
+ -1.0.step(1.0, 0.01) do |n|
+ test_values << n
+ end
+ compare_with_float(test_values, OraNumber,
+ Proc.new {|n| Math::asin(n)},
+ Proc.new {|n| OCI8::Math::asin(n)})
+ end
+
+ # OCI8::Math.atan(x) -> ocinumber
+ def test_math_atan
+ compare_with_float(SMALL_RANGE_VALUES, OraNumber,
+ Proc.new {|n| Math::atan(n)},
+ Proc.new {|n| OCI8::Math::atan(n)})
+ end
+
+ # OCI8::Math.atan2(y, x) -> ocinumber
+ def test_math_atan2
+ compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
+ Proc.new {|x, y| Math::atan2(x, y.to_f)},
+ Proc.new {|x, y| OCI8::Math::atan2(x, y.to_f)})
+ compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
+ Proc.new {|x, y| Math::atan2(y.to_f, x)},
+ Proc.new {|x, y| OCI8::Math::atan2(y.to_f, x)})
+ end
+
+ # OCI8::Math.cos(x) -> ocinumber
+ def test_math_cos
+ compare_with_float(SMALL_RANGE_VALUES, OraNumber,
+ Proc.new {|n| Math::cos(n)},
+ Proc.new {|n| OCI8::Math::cos(n)})
+ end
+
+ # OCI8::Math.cosh(x) -> ocinumber
+ def test_math_cosh
+ compare_with_float(SMALL_RANGE_VALUES, OraNumber,
+ Proc.new {|n| Math::cosh(n)},
+ Proc.new {|n| OCI8::Math::cosh(n)})
+ end
+
+ # OCI8::Math.exp(x) -> ocinumber
+ def test_exp
+ compare_with_float(SMALL_RANGE_VALUES, OraNumber,
+ Proc.new {|n| Math::exp(n)},
+ Proc.new {|n| OCI8::Math::exp(n)})
+ end
+
+ # OCI8::Math.log(numeric) -> ocinumber
+ # OCI8::Math.log(numeric, base_num) -> ocinumber
+ def test_log
+ test_values = LARGE_RANGE_VALUES.reject do |x|
+ # reject minus and zero values
+ x[0,1] == '-' || x == '0'
+ end
+ compare_with_float(test_values, OraNumber,
+ Proc.new {|n| Math::log(n)},
+ Proc.new {|n| OCI8::Math::log(n)})
+ compare_with_float(test_values, OraNumber,
+ Proc.new {|n| Math::log(n)/Math::log(3)},
+ Proc.new {|n| OCI8::Math::log(n, 3)})
+ end
+
+ # OCI8::Math.log10(numeric) -> ocinumber
+ def test_log10
+ test_values = LARGE_RANGE_VALUES.reject do |x|
+ # reject minus and zero values
+ x[0,1] == '-' || x == '0'
+ end
+ compare_with_float(test_values, OraNumber,
+ Proc.new {|n| Math::log10(n)},
+ Proc.new {|n| OCI8::Math::log10(n)})
+ end
+
+ # OCI8::Math.sin(x) -> ocinumber
+ def test_math_sin
+ compare_with_float(SMALL_RANGE_VALUES, OraNumber,
+ Proc.new {|n| Math::sin(n)},
+ Proc.new {|n| OCI8::Math::sin(n)})
+ end
+
+ # OCI8::Math.sinh(x) -> ocinumber
+ def test_math_sinh
+ compare_with_float(SMALL_RANGE_VALUES, OraNumber,
+ Proc.new {|n| Math::sinh(n)},
+ Proc.new {|n| OCI8::Math::sinh(n)})
+ end
+
+ # OCI8::Math.sqrt(numeric) -> ocinumber
+ def test_sqrt
+ test_values = LARGE_RANGE_VALUES.reject do |x|
+ # reject minus values
+ x[0,1] == '-'
+ end
+ compare_with_float(test_values, OraNumber,
+ Proc.new {|n| Math::sqrt(n)},
+ Proc.new {|n| OCI8::Math::sqrt(n)})
+ end
+
+ # OCI8::Math.tan(x) -> ocinumber
+ def test_math_tan
+ test_values = SMALL_RANGE_VALUES.reject do |x|
+ # reject PI/2 and -PI/2.
+ # Those values are +inf and -info
+ radian = x.to_f
+ (radian.abs - Math::PI/2).abs < 0.000001
+ end
+ compare_with_float(test_values, OraNumber,
+ Proc.new {|n| Math::tan(n)},
+ Proc.new {|n| OCI8::Math::tan(n)})
+ end
+
+ # OCI8::Math.tanh() -> ocinumber
+ def test_math_tanh
+ compare_with_float(SMALL_RANGE_VALUES, OraNumber,
+ Proc.new {|n| Math::tanh(n)},
+ Proc.new {|n| OCI8::Math::tanh(n)})
+ end
+
+ # onum % other -> onum
+ # def test_mod
+
+ # onum * other -> onum
+ def test_mul
+ compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
+ Proc.new {|x, y| x * y.to_f})
+ compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
+ Proc.new {|x, y| y.to_f * x})
+ end
+
+ # onum ** other -> onum
+ def test_pow
+ base_values = SMALL_RANGE_VALUES.reject do |x|
+ # reject minus and zero values
+ x[0,1] == '-' || x == '0'
+ end
+ compare_with_float2(base_values, SMALL_RANGE_VALUES,
+ Proc.new {|x, y| x ** y.to_f})
+ compare_with_float2(SMALL_RANGE_VALUES, base_values,
+ Proc.new {|x, y| y.to_f ** x})
+ end
+
+ # onum + other -> onum
+ def test_add
+ compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
+ Proc.new {|x, y| x + y.to_f})
+ compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
+ Proc.new {|x, y| y.to_f + x})
+ end
+
+ # onum - other -> onum
+ def test_minus
+ compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
+ Proc.new {|x, y| x - y.to_f})
+ compare_with_float2(SMALL_RANGE_VALUES, SMALL_RANGE_VALUES,
+ Proc.new {|x, y| y.to_f - x})
+ end
+
+ # -ocinumber -> ocinumber
+ def test_uminus
+ compare_with_float(LARGE_RANGE_VALUES, OraNumber, Proc.new {|n| -n})
+ end
+
+ # onum / other -> onum
+ # TODO: test_div
+
+ # onum <=> other -> -1, 0, +1
+ def test_cmp
+ test_values = SMALL_RANGE_VALUES.collect do |x|
+ x[0,15] # donw the precision to pass this test.
+ end
+ compare_with_float2(test_values, test_values,
+ Proc.new {|x, y| x <=> y.to_f})
+ compare_with_float2(test_values, test_values,
+ Proc.new {|x, y| y.to_f <=> x})
+ end
+
+ # onum.abs -> ocinumber
+ def test_abs
+ compare_with_float(LARGE_RANGE_VALUES, OraNumber, Proc.new {|n| n.abs})
+ end
+
+ # onum.ceil -> integer
+ def test_ceil
+ compare_with_float(LARGE_RANGE_VALUES, Integer, Proc.new {|n| n.ceil})
+ end
+
+ # onum.floor -> integer
+ def test_floor
+ compare_with_float(LARGE_RANGE_VALUES, Integer, Proc.new {|n| n.floor})
+ end
+
+ # onum.round -> integer
+ # onum.round(decplace) -> onum
+ def test_round
+ compare_with_float(LARGE_RANGE_VALUES, Integer, Proc.new {|n| n.round})
+ compare_with_float(LARGE_RANGE_VALUES, OraNumber,
+ Proc.new {|n| (n * 10).round * 0.1},
+ Proc.new {|n| n.round(1)})
+ compare_with_float(LARGE_RANGE_VALUES, OraNumber,
+ Proc.new {|n| (n * 100).round * 0.01},
+ Proc.new {|n| n.round(2)})
+ compare_with_float(LARGE_RANGE_VALUES, OraNumber,
+ Proc.new {|n| (n * 0.1).round * 10},
+ Proc.new {|n| n.round(-1)})
+ end
+
+ # onum.round_prec(digits) -> ocinumber
+ def test_round_prec
+ if OCI8::oracle_client_version >= 810
+ # Oracle 8.1 client or upper
+ compare_with_float2(LARGE_RANGE_VALUES, [1, 2, 3, 5, 10, 20],
+ Proc.new {|x, y|
+ return 0.0 if x == 0.0
+ factor = 10 ** (Math::log10(x.abs).to_i - y + 1)
+ (x / factor).round * factor
+ },
+ Proc.new {|x, y| x.round_prec(y)})
+ else
+ # Oracle 8.0 client
+ assert_raise RuntimeError do
+ OraNumber.new(1).round_prec(1)
+ end
+ end
+ end
+
+ # onum.shift(fixnum) -> ocinumber
+ def test_shift
+ if OCI8::oracle_client_version >= 810
+ # Oracle 8.1 client or upper
+ compare_with_float2(LARGE_RANGE_VALUES, [-5, -4, -3, -1, 0, 1, 2, 3, 4, 5],
+ Proc.new {|x, y| x * (10 ** y)},
+ Proc.new {|x, y| x.shift(y)})
+ else
+ # Oracle 8.0 client
+ assert_raise RuntimeError do
+ OraNumber.new(1).shift(1)
+ end
+ end
+ end
+
+ # onum.to_char(fmt = nil, nls_params = nil) -> string
+ def test_to_char
+ onum = OraNumber.new(123.45)
+ assert_equal(' 123.4500', onum.to_char('99999.9999'))
+ assert_equal(' 0123.4500', onum.to_char('90000.0009'))
+ assert_equal(' 00123.4500', onum.to_char('00000.0000'))
+ assert_equal('123.45', onum.to_char('FM99999.9999'))
+ assert_equal('0123.450', onum.to_char('FM90000.0009'))
+ assert_equal('00123.4500', onum.to_char('FM00000.0000'))
+ assert_equal(' -123.4500',(-onum).to_char('99999.9999'))
+ assert_equal(' -0123.4500',(-onum).to_char('90000.0009'))
+ assert_equal('-00123.4500',(-onum).to_char('00000.0000'))
+ assert_equal('-123.45', (-onum).to_char('FM99999.9999'))
+ assert_equal('-0123.450', (-onum).to_char('FM90000.0009'))
+ assert_equal('-00123.4500',(-onum).to_char('FM00000.0000'))
+ assert_equal(' 0,123.4500', onum.to_char('0G000D0000', "NLS_NUMERIC_CHARACTERS = '.,'"))
+ assert_equal(' 0.123,4500', onum.to_char('0G000D0000', "NLS_NUMERIC_CHARACTERS = ',.'"))
+ assert_equal('Ducat123.45', onum.to_char('FML9999.999', "NLS_CURRENCY = 'Ducat'"))
+ end
+
+ # onum.to_f -> float
+ def test_to_f
+ LARGE_RANGE_VALUES.each do |x|
+ expected_val = x.to_f
+ actual_val = OraNumber.new(x).to_f
+ delta = [expected_val.abs * 1.0e-12, 1.0e-14].max
+ assert_in_delta(expected_val, actual_val, delta, x)
+ end
+ end
+
+ # onum.to_i -> integer
+ def test_to_i
+ LARGE_RANGE_VALUES.each do |x|
+ expected_val = x.to_i
+ actual_val = OraNumber.new(x).to_i
+ assert_equal(expected_val, actual_val, x)
+ end
+ end
+
+ # onum.to_s -> string
+ def test_to_s
+ LARGE_RANGE_VALUES.each do |x|
+ expected_val = x
+ actual_val = OraNumber.new(x).to_s
+ assert_equal(expected_val, actual_val, x)
+ end
+ end
+
+ # onum.truncate -> integer
+ # onum.truncate(decplace) -> ocinumber
+ # TODO: test_truncate
+
+ # onum.zero? -> true or false
+ def test_zero_p
+ LARGE_RANGE_VALUES.each do |x|
+ expected_val = x.to_f.zero?
+ actual_val = OraNumber.new(x).zero?
+ assert_equal(expected_val, actual_val, x)
+ end
+ end
end
More information about the ruby-oci8-commit
mailing list