diff --git a/js/pyson.js b/js/pyson.js new file mode 100644 index 0000000000..90e5044c2d --- /dev/null +++ b/js/pyson.js @@ -0,0 +1,632 @@ +/* This file is part of Tryton. The COPYRIGHT file at the top level of + this repository contains the full copyright notices and license terms. */ +'use strict'; + +Sao.PYSON = {}; + +Sao.PYSON.PYSON = Class(Object, { + init: function() { + }, + pyson: function() { + throw 'NotImplementedError'; + }, + types: function() { + throw 'NotImplementedError'; + } +}); + +Sao.PYSON.PYSON.eval = function(value, context) { + throw 'NotImplementedError'; +}; + +Sao.PYSON.Encoder = Class(Object, { + encode: function(pyson) { + return JSON.stringify(pyson, function(k, v) { + if (v instanceof Sao.PYSON.PYSON) { + return v.pyson(); + } else if (v instanceof Date) { + if (v.getHours() || v.getMinutes() || v.getSeconds() || + v.getMilliseconds()) { + return Sao.PYSON.DateTime( + v.getFullYear(), + v.getMonth(), + v.getDate(), + v.getHours(), + v.getMinutes(), + v.getSeconds(), + v.getMilliseconds()).pyson(); + } else { + return Sao.PYSON.DateTime( + v.getFullYear(), + v.getMonth(), + v.getDate()).pyson(); + } + } + return v; + }); + } +}); + +Sao.PYSON.Decoder = Class(Object, { + init: function(context) { + this.__context = context || {}; + }, + decode: function(str) { + var reviver = function(k, v) { + if (typeof v == 'object') { + var cls = Sao.PYSON[v.__class__]; + if (cls) { + return cls.eval(v, this.__context); + } + } + return v; + }; + return JSON.parse(str, reviver.bind(this)); + } +}); + +Sao.PYSON.Eval = Class(Sao.PYSON.PYSON, { + init: function(value, default_) { + if (default_ === undefined) { + default_ = ''; + } + Sao.PYSON.Eval._super.init.call(this); + this._value = value; + this._default = default_; + }, + pyson: function() { + return { + '__class__': 'Eval', + 'v': this._value, + 'd': this._default + }; + }, + types: function() { + if (this._default instanceof Sao.PYSON.PYSON) { + return this._default.types(); + } else { + return [typeof this._default]; + } + } +}); + +Sao.PYSON.Eval.eval = function(value, context) { + if (value.v in context) { + return context[value.v]; + } else { + return value.d; + } +}; + +Sao.PYSON.Not = Class(Sao.PYSON.PYSON, { + init: function(value) { + Sao.PYSON.Not._super.init.call(this); + if (value instanceof Sao.PYSON.PYSON) { + if ((jQuery(value.types()).not(['boolean']).length != 0) || + (jQuery(['boolean']).not(value.types()).length != 0)) { + throw 'value must be boolean'; + } + } else { + if (typeof value != 'boolean') { + throw 'value must be boolean'; + } + } + this._value = value; + }, + pyson: function() { + return { + '__class__': 'Not', + 'v': this._value + }; + }, + types: function() { + return ['boolean']; + } +}); + +Sao.PYSON.Not.eval = function(value, context) { + return !value.v; +}; + +Sao.PYSON.Bool = Class(Sao.PYSON.PYSON, { + init: function(value) { + Sao.PYSON.Bool._super.init.call(this); + this._value = value; + }, + pyson: function() { + return { + '__class__': 'Bool', + 'v': this._value + }; + }, + types: function() { + return ['boolean']; + } +}); + +Sao.PYSON.Bool.eval = function(value, context) { + if (value.v instanceof Object) { + return !jQuery.isEmptyObject(value.v); + } else { + return Boolean(value.v); + } +}; + + +Sao.PYSON.And = Class(Sao.PYSON.PYSON, { + init: function(statements) { + Sao.PYSON.And._super.init.call(this); + for (var i = 0, len = statements.length; i < len; i++) { + var statement = statements[i]; + if (statement instanceof Sao.PYSON.PYSON) { + if ((jQuery(statement.types()).not(['boolean']).length != 0) || + (jQuery(['boolean']).not(statement.types()).length != 0)) { + throw 'statement must be boolean'; + } + } else { + if (typeof statement != 'boolean') { + throw 'statement must be boolean'; + } + } + } + if (statements.length < 2) { + throw 'must have at least 2 statements'; + } + this._statements = statements; + }, + pyson: function() { + return { + '__class__': 'And', + 's': this._statements + }; + }, + types: function() { + return ['boolean']; + } +}); + +Sao.PYSON.And.eval = function(value, context) { + var result = true; + for (var i = 0, len = value.s.length; i < len; i++) { + var statement = value.s[i]; + result = result && statement; + } + return result; +}; + + +Sao.PYSON.Or = Class(Sao.PYSON.And, { + pyson: function() { + var result = Sao.PYSON.Or._super.pyson.call(this); + result['__class__'] = 'Or'; + return result; + } +}); + +Sao.PYSON.Or.eval = function(value, context) { + var result = false; + for (var i = 0, len = value.s.length; i < len; i++) { + var statement = value.s[i]; + result = result || statement; + } + return result; +}; + +Sao.PYSON.Equal = Class(Sao.PYSON.PYSON, { + init: function(statement1, statement2) { + Sao.PYSON.Equal._super.init.call(this); + if (statement1 instanceof Sao.PYSON.PYSON) { + var types1 = statement1.types(); + } else { + var types1 = [typeof statement1]; + } + if (statement2 instanceof Sao.PYSON.PYSON) { + var types2 = statement2.types(); + } else { + var types2 = [typeof statement2]; + } + if ((jQuery(types1).not(types2).length != 0) || + (jQuery(types2).not(types1).length != 0)) { + throw 'statements must have the same type'; + } + this._statement1 = statement1; + this._statement2 = statement2; + }, + pyson: function() { + return { + '__class__': 'Equal', + 's1': this._statement1, + 's2': this._statement2 + }; + }, + types: function() { + return ['boolean']; + } +}); + +Sao.PYSON.Equal.eval = function(value, context) { + return value.s1 == value.s2; +}; + +Sao.PYSON.Greater = Class(Sao.PYSON.PYSON, { + init: function(statement1, statement2, equal) { + Sao.PYSON.Greater._super.init.call(this); + var statements = [statement1, statement2]; + for (var i = 0; i < 2; i++) { + var statement = statements[i]; + if (statement instanceof Sao.PYSON.PYSON) { + if (jQuery(statement).not([int, float]).length != 0) { + throw 'statement must be an integer or a float'; + } + } else { + if (typeof statement != 'number') { + throw 'statement must be an integer or a float'; + } + } + } + if (equal === undefined) { + equal = false; + } + if (equal instanceof Sao.PYSON.PYSON) { + if ((jQuery(equal.types()).not(['boolean']).length != 0) || + (jQuery(['boolean']).not(equal.types()).length != 0)) { + throw 'equal must be boolean'; + } + } else { + if (typeof equal != 'boolean') { + throw 'equal must be boolean'; + } + } + this._statement1 = statement1; + this._statement2 = statement2; + this._equal = equal; + }, + pyson: function() { + return { + '__class__': 'Greater', + 's1': this._statement1, + 's2': this._statement2, + 'e': this._equal + }; + }, + types: function() { + return ['boolean']; + } +}); + +Sao.PYSON.Greater._convert = function(value) { + value = jQuery.extend({}, value); + value.s1 = Number(value.s1); + value.s2 = Number(value.s2); + return value; +}; + +Sao.PYSON.Greater.eval = function(value, context) { + value = Sao.PYSON.Greater._convert(value); + if (value.e) { + return value.s1 >= value.s2; + } else { + return value.s1 > value.s2; + } +}; + +Sao.PYSON.Less = Class(Sao.PYSON.Greater, { + pyson: function() { + var result = Sao.PYSON.Less._super.pyson.call(this); + result['__class__'] = 'Less'; + return result; + } +}); + +Sao.PYSON.Less._convert = Sao.PYSON.Greater._convert; + +Sao.PYSON.Less.eval = function(value, context) { + value = Sao.PYSON.Less._convert(value); + if (value.e) { + return value.s1 <= value.s2; + } else { + return value.s1 < value.s2; + } +}; + +Sao.PYSON.If = Class(Sao.PYSON.PYSON, { + init: function(condition, then_statement, else_statement) { + Sao.PYSON.If._super.init.call(this); + if (condition instanceof Sao.PYSON.PYSON) { + if ((jQuery(condition.types()).not(['boolean']).length != 0) || + (jQuery(['boolean']).not(condition.types()).length != 0)) { + throw 'condition must be boolean'; + } + } else { + if (typeof condition != 'boolean') { + throw 'condition must be boolean'; + } + } + if (then_statement instanceof Sao.PYSON.PYSON) { + var then_types = then_statement.types(); + } else { + var then_types = [typeof then_statement]; + } + if (else_statement === undefined) { + else_statement = null; + } + if (else_statement instanceof Sao.PYSON.PYSON) { + var else_types = else_statement.types(); + } else { + var else_types = [typeof else_statement]; + } + if ((jQuery(then_types).not(else_types).length != 0) || + (jQuery(else_types).not(then_types).length != 0)) { + throw 'then and else statements must be the same type'; + } + this._condition = condition; + this._then_statement = then_statement; + this._else_statement = else_statement; + }, + pyson: function() { + return { + '__class__': 'If', + 'c': this._condition, + 't': this._then_statement, + 'e': this._else_statement + }; + }, + types: function() { + if (this._then_statement instanceof Sao.PYSON.PYSON) { + return this._then_statement.types(); + } else { + return [typeof this._then_statement]; + } + } +}); + +Sao.PYSON.If.eval = function(value, context) { + if (value.c) { + return value.t; + } else { + return value.e; + } +}; + +Sao.PYSON.Get = Class(Sao.PYSON.PYSON, { + init: function(obj, key, default_) { + Sao.PYSON.Get._super.init.call(this); + if (default_ === undefined) { + default_ = null; + } + if (obj instanceof Sao.PYSON.PYSON) { + if ((jQuery(obj.types()).not(['object']).length != 0) || + (jQuery(['object']).not(obj.types()).length != 0)) { + throw 'obj must be a dict'; + } + } else { + if (!(obj instanceof Object)) { + throw 'obj must be a dict'; + } + } + this._obj = obj; + if (key instanceof Sao.PYSON.PYSON) { + if ((jQuery(key.types()).not(['string']).length != 0) || + (jQuery(['string']).not(key.types()).length != 0)) { + throw 'key must be a string'; + } + } else { + if (typeof key != 'string') { + throw 'key must be a string'; + } + } + this._key = key; + this._default = default_; + }, + pyson: function() { + return { + '__class__': 'Get', + 'v': this._obj, + 'k': this._key, + 'd': this._default + }; + }, + types: function() { + if (this._default instanceof Sao.PYSON.PYSON) { + return this._default.types(); + } else { + return [typeof this._default]; + } + } +}); + +Sao.PYSON.Get.eval = function(value, context) { + if (value.k in value.v) { + return value.v[value.k]; + } else { + return value.d; + } +}; + +Sao.PYSON.In = Class(Sao.PYSON.PYSON, { + init: function(key, obj) { + Sao.PYSON.In._super.init.call(this); + if (key instanceof Sao.PYSON.PYSON) { + if (jQuery(key.types()).not(['string', 'number']).length != 0) { + throw 'key must be a string or a number'; + } + } else { + if (['string', 'number'].indexOf(typeof key) < 0) { + throw 'key must be a string or a number'; + } + } + if (obj instanceof Sao.PYSON.PYSON) { + if ((jQuery(obj.types()).not(['object']).length != 0) || + (jQuery(['object']).not(obj.types()).length != 0)) { + throw 'obj must be a dict or a list'; + } + } else { + if (!(obj instanceof Object)) { + throw 'obj must be a dict or a list'; + } + } + this._key = key; + this._obj = obj; + }, + pyson: function() { + return {'__class__': 'In', + 'k': this._key, + 'v': this._obj + }; + }, + types: function() { + return ['boolean']; + } +}); + +Sao.PYSON.In.eval = function(value, context) { + if (value.v.indexOf) { + return value.v.indexOf(value.k) >= 0; + } else { + return !!value.v[value.k]; + } +}; + +Sao.PYSON.Date = Class(Sao.PYSON.PYSON, { + init: function(year, month, day, delta_years, delta_months, delta_days) { + Sao.PYSON.Date._super.init.call(this); + if (year === undefined) year = null; + if (month === undefined) month = null; + if (day === undefined) day = null; + if (delta_years === undefined) delta_years = 0; + if (delta_months === undefined) delta_months = 0; + if (delta_days === undefined) delta_days = 0; + + this._test(year, 'year'); + this._test(month, 'month'); + this._test(day, 'day'); + this._test(delta_years, 'delta_years'); + this._test(delta_days, 'delta_days'); + this._test(delta_months, 'delta_months'); + + this._year = year; + this._month = month; + this._day = day; + this._delta_years = delta_years; + this._delta_months = delta_months; + this._delta_days = delta_days; + }, + pyson: function() { + return { + '__class__': 'Date', + 'y': this._year, + 'M': this._month, + 'd': this._day, + 'dy': this._delta_years, + 'dM': this._delta_months, + 'dd': this._delta_days + }; + }, + types: function() { + return ['object']; + }, + _test: function(value, name) { + if (value instanceof Sao.PYSON.PYSON) { + if (jQuery(value.types()).not( + ['number', typeof null]).length != 0) { + throw name + ' must be an integer or None'; + } + } else { + if ((typeof value != 'number') && (value !== null)) { + throw name + ' must be an integer or None'; + } + } + } +}); + +Sao.PYSON.Date.eval = function(value, context) { + var date = new Date(); + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + if (value.y) date.setFullYear(value.y); + if (value.M) date.setMonth(value.M); + if (value.d) date.setDate(value.d); + var year = date.getFullYear(); + var month = date.getMonth(); + var day = date.getDate(); + if (value.dy) date.setFullYear(year + value.dy); + if (value.dM) date.setMonth(month + value.dM); + if (value.dd) date.setDate(day + value.dd); + return date; +}; + +Sao.PYSON.DateTime = Class(Sao.PYSON.Date, { + init: function(year, month, day, hour, minute, second, microsecond, + delta_years, delta_months, delta_days, delta_hours, + delta_minutes, delta_seconds, delta_microseconds) { + Sao.PYSON.DateTime._super.init.call(this, year, month, day, + delta_years, delta_months, delta_days); + if (hour === undefined) hour = null; + if (minute === undefined) minute = null; + if (second === undefined) second = null; + if (microsecond === undefined) microsecond = null; + if (delta_hours === undefined) delta_hours = 0; + if (delta_minutes === undefined) delta_minutes = 0; + if (delta_seconds === undefined) delta_seconds = 0; + if (delta_microseconds === undefined) delta_microseconds = 0; + + this._test(hour, 'hour'); + this._test(minute, 'minute'); + this._test(second, 'second'); + this._test(microsecond, 'microsecond'); + this._test(delta_hours, 'delta_hours'); + this._test(delta_minutes, 'delta_minutes'); + this._test(delta_seconds, 'delta_seconds'); + this._test(delta_microseconds, 'delta_microseconds'); + + this._hour = hour; + this._minute = minute; + this._second = second; + this._microsecond = microsecond; + this._delta_hours = delta_hours; + this._delta_minutes = delta_minutes; + this._delta_seconds = delta_seconds; + this._delta_microseconds = delta_microseconds; + }, + pyson: function() { + var result = Sao.PYSON.DateTime._super.pyson.call(this); + result['__class__'] = 'DateTime'; + result['h'] = this._hour; + result['m'] = this._minute; + result['s'] = this._second; + result['ms'] = this._microsecond; + result['dh'] = this._delta_hours; + result['dm'] = this._delta_minutes; + result['ds'] = this._delta_seconds; + result['dms'] = this._delta_microseconds; + return result; + } +}); + +Sao.PYSON.DateTime.eval = function(value, context) { + var date = new Date(); + if (value.y) date.setFullYear(value.y); + if (value.M) date.setMonth(value.M); + if (value.d) date.setDate(value.d); + if (value.h !== undefined) date.setHours(value.h); + if (value.m !== undefined) date.setMinutes(value.m); + if (value.s !== undefined) date.setSeconds(value.s); + if (value.ms !== undefined) date.setMilliseconds(value.ms / 100); + var year = date.getFullYear(); + var month = date.getMonth(); + var day = date.getDate(); + var hour = date.getHours(); + var minute = date.getMinutes(); + var second = date.getSeconds(); + var millisecond = date.getMilliseconds(); + if (value.dy) date.setFullYear(year + value.dy); + if (value.dM) date.setMonth(month + value.dM); + if (value.dd) date.setDate(day + value.dd); + if (value.dh) date.setHours(hour + value.dh); + if (value.dm) date.setMinutes(minute + value.dm); + if (value.ds) date.setSeconds(second + value.ds); + if (value.dms) date.setMilliseconds(millisecond + value.dms / 100); + return date; +}; diff --git a/tests/index.html b/tests/index.html index 92f77b3f59..3b1de9ca75 100644 --- a/tests/index.html +++ b/tests/index.html @@ -21,6 +21,7 @@ this repository contains the full copyright notices and license terms. --> + diff --git a/tests/sao.js b/tests/sao.js index afeb235188..bc2bf1c955 100644 --- a/tests/sao.js +++ b/tests/sao.js @@ -10,6 +10,11 @@ var SaoTest = { 'dbname': 'test_' + new Date().getTime() }; +SaoTest.compare = function(arr1, arr2) { + return (jQuery(arr1).not(arr2).length == 0 && + jQuery(arr2).not(arr1).length == 0); +}; + QUnit.test('JSON', function() { var tests = { 'array': [1, 2, 3], @@ -29,6 +34,708 @@ QUnit.test('JSON', function() { } }); +QUnit.test('PYSON.Eval', function() { + var value = new Sao.PYSON.Eval('test').pyson(); + QUnit.strictEqual(value.__class__, 'Eval', "Eval('test').pyson()"); + QUnit.strictEqual(value.v, 'test', "Eval('test').pyson()"); + QUnit.strictEqual(value.d, '', "Eval('test').pyson()"); + var value = new Sao.PYSON.Eval('test', 'foo').pyson(); + QUnit.strictEqual(value.__class__, 'Eval', "Eval('test', 'foo').pyson()"); + QUnit.strictEqual(value.v, 'test', "Eval('test', 'foo').pyson()"); + QUnit.strictEqual(value.d, 'foo', "Eval('test', 'foo').pyson()"); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.Eval('test', 'foo').types(), + [typeof 'foo']), "Eval('test', 'foo').types()"); + QUnit.ok(SaoTest.compare(new Sao.PYSON.Eval('test', 1).types(), + [typeof 1]), "Eval('test', 1).types()"); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Eval('test', 0)); + QUnit.strictEqual(new Sao.PYSON.Decoder({test: 1}).decode(eval_), 1, + "decode(Eval('test', 0))"); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), 0, + "decode(Eval('test', 0))"); +}); + +QUnit.test('PYSON Not', function() { + var value = new Sao.PYSON.Not(true).pyson(); + QUnit.strictEqual(value.__class__, 'Not', 'Not(true).pyson()'); + QUnit.strictEqual(value.v, true, 'Not(true).pyson()'); + + QUnit.throws(function() { + new Sao.PYSON.Not('foo'); + }, 'value must be boolean', "Not('foo')"); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.Not(true).types(), ['boolean']), + 'Not(true).types()'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Not(true)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Not(true))'); + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Not(false)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Not(false))'); +}); + +QUnit.test('PYSON Bool', function() { + var value = new Sao.PYSON.Bool('test').pyson(); + QUnit.strictEqual(value.__class__, 'Bool', "Bool('test').pyson()"); + QUnit.strictEqual(value.v, 'test', "Bool('test').pyson()"); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.Bool('test').types(), ['boolean']), + "Bool('test').types()"); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Bool(true)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Bool(true))'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Bool(false)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Bool(false))'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Bool('test')); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + "decode(Bool('test'))"); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Bool('')); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + "decode(Bool(''))"); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Bool(1)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Bool(1))'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Bool(0)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Bool(0))'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Bool(['test'])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + "decode(Bool(['test']))"); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Bool([])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Bool([]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Bool({foo: 'bar'})); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + "decode(Bool({foo: 'bar'}))"); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Bool({})); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Bool({}))'); +}); + +QUnit.test('PYSON And', function() { + var value = new Sao.PYSON.And([true, false]).pyson(); + QUnit.strictEqual(value.__class__, 'And', 'And([true, false]).pyson()'); + QUnit.ok(SaoTest.compare(value.s, [true, false]), + 'And([true, false]).pyson()'); + + QUnit.throws(function() { + new Sao.PYSON.And(['test', false]); + }, 'statement must be boolean', "And(['test', false])"); + QUnit.throws(function() { + new Sao.PYSON.And([true, 'test']); + }, 'statement must be boolean', "And([true, 'test'])"); + QUnit.throws(function() { + new Sao.PYSON.And([true, false, 'test']); + }, 'statement must be boolean', "And([true, false, 'test'])"); + QUnit.throws(function() { + new Sao.PYSON.And([true]); + }, 'must have at least 2 statements', 'And([true])'); + QUnit.throws(function() { + new Sao.PYSON.And([]); + }, 'must have at least 2 statements', 'And([])'); + QUnit.throws(function() { + new Sao.PYSON.And(); + }, 'must have at least 2 statements', 'And([])'); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.And([true, false]).types(), + ['boolean']), 'And([true, false]).types()'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.And([true, true])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(And([true, true]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.And([true, true, true])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(And([true, true, true]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.And([true, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(And([true, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.And([false, true])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(And([false, true]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.And([false, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(And([false, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.And([false, false, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(And([false, false, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.And([true, false, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(And([true, false, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.And([false, true, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(And([false, true, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.And([false, false, true])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(And([false, false, true]))'); +}); + +QUnit.test('PYSON Or', function() { + var value = new Sao.PYSON.Or([true, false]).pyson(); + QUnit.strictEqual(value.__class__, 'Or', 'Or([true, false]).pyson()'); + QUnit.ok(SaoTest.compare(value.s, [true, false]), + 'Or([true, false]).pyson()'); + + QUnit.throws(function() { + new Sao.PYSON.Or(['test', false]); + }, 'statement must be boolean', "Or(['test', false])"); + QUnit.throws(function() { + new Sao.PYSON.Or([true, 'test']); + }, 'statement must be boolean', "Or([true, 'test'])"); + QUnit.throws(function() { + new Sao.PYSON.Or([true, false, 'test']); + }, 'statement must be boolean', "Or([true, false, 'test'])"); + QUnit.throws(function() { + new Sao.PYSON.Or([true]); + }, 'must have at least 2 statements', 'Or([true])'); + QUnit.throws(function() { + new Sao.PYSON.Or([]); + }, 'must have at least 2 statements', 'Or([])'); + QUnit.throws(function() { + new Sao.PYSON.Or(); + }, 'must have at least 2 statements', 'Or([])'); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.Or([true, false]).types(), + ['boolean']), 'Or([true, false]).types()'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Or([true, true])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Or([true, true]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Or([true, true, true])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Or([true, true, true]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Or([true, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Or([true, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Or([false, true])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Or([false, true]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Or([false, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Or([false, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Or([false, false, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Or([false, false, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Or([true, false, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Or([true, false, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Or([false, true, false])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Or([false, true, false]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Or([false, false, true])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Or([false, false, true]))'); +}); + +QUnit.test('PYSON Equal', function() { + var value = new Sao.PYSON.Equal('test', 'test').pyson(); + QUnit.strictEqual(value.__class__, 'Equal', + "Equal('test', 'test').pyson()"); + QUnit.strictEqual(value.s1, 'test', "Equal('test', 'test').pyson()"); + QUnit.strictEqual(value.s2, 'test', "Equal('test', 'test').pyson()"); + + QUnit.throws(function() { + new Sao.PYSON.Equal('test', true); + }, 'statements must have the same type'); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.Equal('test', 'test').types(), + ['boolean']), "Equal('test', 'test').types()"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Equal('test', 'test')); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + "decode(Equal('test', 'test'))"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Equal('foo', 'bar')); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + "decode(Equal('test', 'test'))"); +}); + +QUnit.test('PYSON Greater', function() { + var value = new Sao.PYSON.Greater(1, 0).pyson(); + QUnit.strictEqual(value.__class__, 'Greater', 'Greater(1, 0).pyson()'); + QUnit.strictEqual(value.s1, 1, 'Greater(1, 0).pyson()'); + QUnit.strictEqual(value.s2, 0, 'Greater(1, 0).pyson()'); + QUnit.strictEqual(value.e, false, 'Greater(1, 0).pyson()'); + + QUnit.throws(function() { + new Sao.PYSON.Greater('test', 0); + }, 'statement must be an integer or a float'); + QUnit.throws(function() { + new Sao.PYSON.Greater(1, 'test'); + }, 'statement must be an integer or a float'); + QUnit.throws(function() { + new Sao.PYSON.Greater(1, 0, 'test'); + }, 'equal must be boolean'); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.Greater(1, 0).types(), ['boolean']), + 'Greater(1, 0).types()'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Greater(1, 0)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Greater(1, 0))'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Greater(0, 1)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Greater(0, 1))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Greater(1, 0, true)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Greater(1, 0, true))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Greater(0, 1, true)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Greater(0, 1, true))'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Greater(1, 1)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Greater(1, 1))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Greater(1, 1, true)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Greater(1, 1, true))'); +}); + +QUnit.test('PYSON Less', function() { + var value = new Sao.PYSON.Less(1, 0).pyson(); + QUnit.strictEqual(value.__class__, 'Less', 'Less(1, 0).pyson()'); + QUnit.strictEqual(value.s1, 1, 'Less(1, 0).pyson()'); + QUnit.strictEqual(value.s2, 0, 'Less(1, 0).pyson()'); + QUnit.strictEqual(value.e, false, 'Less(1, 0).pyson()'); + + QUnit.throws(function() { + new Sao.PYSON.Less('test', 0); + }, 'statement must be an integer or a float'); + QUnit.throws(function() { + new Sao.PYSON.Less(1, 'test'); + }, 'statement must be an integer or a float'); + QUnit.throws(function() { + new Sao.PYSON.Less(1, 0, 'test'); + }, 'equal must be boolean'); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.Less(1, 0).types(), ['boolean']), + 'Less(1, 0).types()'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Less(1, 0)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Less(1, 0))'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Less(0, 1)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Less(0, 1))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Less(1, 0, true)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Less(1, 0, true))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Less(0, 1, true)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Less(0, 1, true))'); + + var eval_ = new Sao.PYSON.Encoder().encode(new Sao.PYSON.Less(1, 1)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(Less(1, 1))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Less(1, 1, true)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(Less(1, 1, true))'); +}); + +QUnit.test('PYSON If', function() { + var value = new Sao.PYSON.If(true, 'foo', 'bar').pyson(); + QUnit.strictEqual(value.__class__, 'If', "If(true, 'foo', 'bar')"); + QUnit.strictEqual(value.c, true, "If(true, 'foo', 'bar')"); + QUnit.strictEqual(value.t, 'foo', "If(true, 'foo', 'bar')"); + QUnit.strictEqual(value.e, 'bar', "If(true, 'foo', 'bar')"); + + QUnit.throws(function() { + new Sao.PYSON.If('test', 'foo', 'bar'); + }, 'condition must be boolean'); + QUnit.throws(function() { + new Sao.PYSON.If(true, 'foo', false); + }, 'then and else statements must be the same type'); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.If(true, 'foo', 'bar').types(), + [typeof 'foo']), "If(true, 'foo', 'bar').types()"); + QUnit.ok(SaoTest.compare(new Sao.PYSON.If(true, false, true).types(), + [typeof true]), 'If(true, false, true).types()'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.If(true, 'foo', 'bar')); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), 'foo', + "decode(If(true, 'foo', 'bar'))"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.If(false, 'foo', 'bar')); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), 'bar', + "decode(If(false, 'foo', 'bar'))"); +}); + +QUnit.test('PYSON Get', function() { + var value = new Sao.PYSON.Get({foo: 'bar'}, 'foo', 'default').pyson(); + QUnit.strictEqual(value.__class__, 'Get', + "Get({foo: 'bar'}, 'foo', 'default').pyson()"); + QUnit.strictEqual(value.v.foo, 'bar', + "Get({foo: 'bar'}, 'foo', 'default').pyson()"); + QUnit.strictEqual(value.k, 'foo', + "Get({foo: 'bar'}, 'foo', 'default').pyson()"); + QUnit.strictEqual(value.d, 'default', + "Get({foo: 'bar'}, 'foo', 'default').pyson()"); + + QUnit.throws(function() { + new Sao.PYSON.Get('test', 'foo', 'default'); + }, 'obj must be a dict'); + QUnit.throws(function() { + new Sao.PYSON.Get({}, 1, 'default'); + }, 'key must be a string'); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.Get({}, 'foo', 'default').types(), + [typeof '']), "Get({}, 'foo', 'default').types()"); + QUnit.ok(SaoTest.compare(new Sao.PYSON.Get({}, 'foo', true).types(), + [typeof true]), "Get({}, 'foo', true).types()"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Get({foo: 'bar'}, 'foo', 'default')); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), 'bar', + "decode(Get({foo: 'bar'}, 'foo', 'default'))"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Get({foo: 'bar'}, 'test', 'default')); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), 'default', + "decode(Get({foo: 'bar'}, 'test', 'default'))"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Get({}, 'foo', 'default')); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), 'default', + "decode(Get({}, 'foo', 'default'))"); +}); + +QUnit.test('PYSON In', function() { + var value = new Sao.PYSON.In('foo', {foo: 'bar'}).pyson(); + QUnit.strictEqual(value.__class__, 'In', + "In('foo', {foo: 'bar'}).pyson()"); + QUnit.strictEqual(value.k, 'foo', + "In('foo', {foo: 'bar'}).pyson()"); + QUnit.strictEqual(value.v.foo, 'bar', + "In('foo', {foo: 'bar'}).pyson()"); + + QUnit.throws(function() { + new Sao.PYSON.In({}, {}); + }, 'key must be a string or a number'); + QUnit.throws(function() { + new Sao.PYSON.In('test', 'foo'); + }, 'obj must be a dict or a list'); + + QUnit.ok(SaoTest.compare(new Sao.PYSON.In('foo', {}).types(), ['boolean']), + "In('foo', {}).types()"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.In('foo', {foo: 'bar'})); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + "decode(In('foo', {foo: 'bar'}))"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.In('1', {1: 'bar'})); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + "decode(In('1', {1: 'bar'}))"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.In('test', {foo: 'bar'})); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + "decode(In('test', {foo: 'bar'}))"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.In('foo', ['foo'])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + "decode(In('foo', ['foo']))"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.In(1, [1])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), true, + 'decode(In(1, [1]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.In('test', ['foo'])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + "decode(In('test', ['foo']))"); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.In(1, [2])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + 'decode(In(1, [2]))'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.In('test', [])); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_), false, + "decode(In('test', []))"); +}); + +QUnit.test('PYSON Date', function() { + var value = new Sao.PYSON.Date(2010, 1, 12, -1, 12, -7).pyson(); + QUnit.strictEqual(value.__class__, 'Date', + 'Date(2010, 1, 12, -1, 12, -7).pyson()'); + QUnit.strictEqual(value.y, 2010, + 'Date(2010, 1, 12, -1, 12, -7).pyson()'); + QUnit.strictEqual(value.M, 1, + 'Date(2010, 1, 12, -1, 12, -7).pyson()'); + QUnit.strictEqual(value.d, 12, + 'Date(2010, 1, 12, -1, 12, -7).pyson()'); + QUnit.strictEqual(value.dy, -1, + 'Date(2010, 1, 12, -1, 12, -7).pyson()'); + QUnit.strictEqual(value.dM, 12, + 'Date(2010, 1, 12, -1, 12, -7).pyson()'); + QUnit.strictEqual(value.dd, -7, + 'Date(2010, 1, 12, -1, 12, -7).pyson()'); + + QUnit.throws(function() { + new Sao.PYSON.Date('test', 1, 12, -1, 12, -7); + }, 'year must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.Date(2010, 'test', 12, -1, 12, -7); + }, 'month must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.Date(2010, 1, 'test', -1, 12, -7); + }, 'day must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.Date(2010, 1, 12, 'test', 12, -7); + }, 'delta_years must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.Date(2010, 1, 12, -1, 'test', -7); + }, 'delta_months must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.Date(2010, 1, 12, -1, 12, 'test'); + }, 'delta_days must be an integer or None'); + + QUnit.ok(SaoTest.compare( + new Sao.PYSON.Date(2010, 1, 12, -1, 12, -7).types(), + ['object']), 'Date(2010, 1, 12, -1, 12, -7).types()'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Date(2010, 1, 12)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 1, 12).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Date(2010, 1, 12, -1)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2009, 1, 12).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Date(2010, 1, 12, 0, 12)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2011, 1, 12).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Date(2010, 1, 12, 0, 0, -7)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 1, 5).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.Date(2010, 2, 22)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 2, 22).valueOf()); +}); + +QUnit.test('PYSON DateTime', function() { + var value = new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, + -1, 12, -7, 2, 15, 30, 1).pyson(); + QUnit.strictEqual(value.__class__, 'DateTime', + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.y, 2010, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.M, 1, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.d, 12, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.h, 10, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.m, 30, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.s, 20, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.ms, 0, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.dy, -1, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.dM, 12, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.dd, -7, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.dh, 2, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.dm, 15, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.ds, 30, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + QUnit.strictEqual(value.dms, 1, + 'Date(2010, 1, 12, 10, 30, 20, 0, -1, 12, -7, 2, 15, 30, 1).pyson()'); + + QUnit.throws(function() { + new Sao.PYSON.DateTime('test', 1, 12, 10, 30, 20, 0, + -1, 12, -7, 2, 15, 30, 1); + }, 'year must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 'test', 12, 10, 30, 20, 0, + -1, 12, -7, 2, 15, 30, 1); + }, 'month must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 'test', 10, 30, 20, 0, + -1, 12, -7, 2, 15, 30, 1); + }, 'day must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 'test', 30, 20, 0, + -1, 12, -7, 2, 15, 30, 1); + }, 'hour must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 'test', 20, 0, + -1, 12, -7, 2, 15, 30, 1); + }, 'minute must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 'test', 0, + -1, 12, -7, 2, 15, 30, 1); + }, 'second must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 'test', + -1, 12, -7, 2, 15, 30, 1); + }, 'microsecond must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, + 'test', 12, -7, 2, 15, 30, 1); + }, 'delta_years must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, + -1, 'test', -7, 2, 15, 30, 1); + }, 'delta_months must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, + -1, 12, 'test', 2, 15, 30, 1); + }, 'delta_days must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, + -1, 12, -7, 'test', 15, 30, 1); + }, 'delta_hours must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, + -1, 12, -7, 2, 'test', 30, 1); + }, 'delta_minutes must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, + -1, 12, -7, 2, 15, 'test', 1); + }, 'delta_seconds must be an integer or None'); + QUnit.throws(function() { + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, + -1, 12, -7, 2, 15, 30, 'test'); + }, 'delta_microseconds must be an integer or None'); + + QUnit.ok(SaoTest.compare( + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, + -1, 12, -7, 2, 15, 30, 1).types(), + ['object']), 'DateTime(2010, 1, 12, 10, 30, 20, 0, ' + + '-1, 12, -7, 2, 15, 30, 1).types()'); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 1, 12, 10, 30, 20, 0).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, -1)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2009, 1, 12, 10, 30, 20, 0).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, 0, 12)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2011, 1, 12, 10, 30, 20, 0).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, 0, 0, -7)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 1, 5, 10, 30, 20, 0).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, 0, 0, 0, 0, 12)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 1, 12, 22, 30, 20, 0).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, + 0, 0, 0, 0, 0, -30)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 1, 12, 10, 0, 20, 0).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, + 0, 0, 0, 0, 0, 0, 30)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 1, 12, 10, 30, 50, 0).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.DateTime(2010, 1, 12, 10, 30, 20, + 0, 0, 0, 0, 0, 0, 0, 200)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 1, 12, 10, 30, 20, 2).valueOf()); + + var eval_ = new Sao.PYSON.Encoder().encode( + new Sao.PYSON.DateTime(2010, 2, 22, 10, 30, 20, 200)); + QUnit.strictEqual(new Sao.PYSON.Decoder().decode(eval_).valueOf(), + new Date(2010, 2, 22, 10, 30, 20, 2).valueOf()); +}); + QUnit.test('CRUD', function() { var run_tests = function() { var User = new Sao.Model('res.user');