From f49ab125f7886ab241ca4bd0cb359729ab0af446 Mon Sep 17 00:00:00 2001 From: bbaia Date: Mon, 18 Oct 2010 08:40:11 +0000 Subject: [PATCH] short-circuit evaluation of logic operators in SpEL [SPRNET-1381] --- src/Spring/Spring.Core/Expressions/OpOR.cs | 166 +++++++++--------- src/Spring/Spring.Core/Expressions/OpXOR.cs | 88 +++++----- .../Expressions/ExpressionEvaluatorTests.cs | 7 - .../Expressions/OpANDTests.cs | 46 +++-- .../Expressions/OpORTests.cs | 36 ++-- .../Expressions/OpXORTests.cs | 41 +++-- 6 files changed, 210 insertions(+), 174 deletions(-) diff --git a/src/Spring/Spring.Core/Expressions/OpOR.cs b/src/Spring/Spring.Core/Expressions/OpOR.cs index 2cd62e89..9516720b 100644 --- a/src/Spring/Spring.Core/Expressions/OpOR.cs +++ b/src/Spring/Spring.Core/Expressions/OpOR.cs @@ -1,85 +1,93 @@ -#region License - -/* - * Copyright © 2002-2005 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#endregion - -using System; +#region License + +/* + * Copyright © 2002-2005 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#endregion + +using System; using System.Runtime.Serialization; -using Spring.Util; - -namespace Spring.Expressions -{ - /// - /// Represents OR operator (both, bitwise and logical). - /// - /// Aleksandar Seovic - [Serializable] - public class OpOR : BinaryOperator - { - /// - /// Create a new instance - /// - public OpOR():base() - { - } - - /// - /// Create a new instance - /// - public OpOR(BaseNode left, BaseNode right) - :base(left, right) - { - } - - /// - /// Create a new instance from SerializationInfo - /// - protected OpOR(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the logical OR operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. +using Spring.Util; + +namespace Spring.Expressions +{ + /// + /// Represents OR operator (both, bitwise and logical). + /// + /// Aleksandar Seovic + [Serializable] + public class OpOR : BinaryOperator + { + /// + /// Create a new instance + /// + public OpOR():base() + { + } + + /// + /// Create a new instance + /// + public OpOR(BaseNode left, BaseNode right) + :base(left, right) + { + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpOR(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the logical OR operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) + protected override object Get(object context, EvaluationContext evalContext) { object l = GetLeftValue(context, evalContext); - object r = GetRightValue(context, evalContext); + + if (NumberUtils.IsInteger(l)) + { + object r = GetRightValue(context, evalContext); + if (NumberUtils.IsInteger(r)) + { + return NumberUtils.BitwiseOr(l, r); + } + } + else if (l is Enum) + { + object r = GetRightValue(context, evalContext); + if (l.GetType() == r.GetType()) + { + Type enumType = l.GetType(); + Type integralType = Enum.GetUnderlyingType(enumType); + l = Convert.ChangeType(l, integralType); + r = Convert.ChangeType(r, integralType); + object result = NumberUtils.BitwiseOr(l, r); + return Enum.ToObject(enumType, result); + } + } - if (NumberUtils.IsInteger(l) && NumberUtils.IsInteger(r)) - { - return NumberUtils.BitwiseOr(l, r); - } - else if (l is Enum && l.GetType() == r.GetType()) - { - Type enumType = l.GetType(); - Type integralType = Enum.GetUnderlyingType(enumType); - l = Convert.ChangeType(l, integralType); - r = Convert.ChangeType(r, integralType); - object result = NumberUtils.BitwiseOr(l, r); - return Enum.ToObject(enumType, result); - } - else - return Convert.ToBoolean(l) || Convert.ToBoolean(r); - } - } + return Convert.ToBoolean(l) || + Convert.ToBoolean(GetRightValue(context, evalContext)); + } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Expressions/OpXOR.cs b/src/Spring/Spring.Core/Expressions/OpXOR.cs index 487455ff..a12805a3 100644 --- a/src/Spring/Spring.Core/Expressions/OpXOR.cs +++ b/src/Spring/Spring.Core/Expressions/OpXOR.cs @@ -1,19 +1,19 @@ #region License -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #endregion @@ -30,40 +30,40 @@ namespace Spring.Expressions [Serializable] public class OpXOR : BinaryOperator { - /// - /// Create a new instance - /// + /// + /// Create a new instance + /// public OpXOR() { } - /// - /// Create a new instance - /// - public OpXOR(BaseNode left, BaseNode right) - :base(left, right) - { - } - - /// - /// Create a new instance from SerializationInfo + /// + /// Create a new instance /// - protected OpXOR(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - - /// - /// Returns a value for the logical AND operator node. - /// - /// Context to evaluate expressions against. - /// Current expression evaluation context. + public OpXOR(BaseNode left, BaseNode right) + :base(left, right) + { + } + + /// + /// Create a new instance from SerializationInfo + /// + protected OpXOR(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + /// + /// Returns a value for the logical AND operator node. + /// + /// Context to evaluate expressions against. + /// Current expression evaluation context. /// Node's value. - protected override object Get(object context, EvaluationContext evalContext) - { - object l = GetLeftValue(context, evalContext); - object r = GetRightValue(context, evalContext); - - if (NumberUtils.IsInteger(l) && NumberUtils.IsInteger(r)) + protected override object Get(object context, EvaluationContext evalContext) + { + object l = GetLeftValue(context, evalContext); + object r = GetRightValue(context, evalContext); + + if (NumberUtils.IsInteger(l) && NumberUtils.IsInteger(r)) { return NumberUtils.BitwiseXor(l, r); } @@ -76,7 +76,7 @@ namespace Spring.Expressions object result = NumberUtils.BitwiseXor(l, r); return Enum.ToObject(enumType, result); } - return Convert.ToBoolean(l) ^ Convert.ToBoolean(r); + return Convert.ToBoolean(l) ^ Convert.ToBoolean(r); } } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Expressions/ExpressionEvaluatorTests.cs b/test/Spring/Spring.Core.Tests/Expressions/ExpressionEvaluatorTests.cs index 73e7b23b..811eadba 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/ExpressionEvaluatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/ExpressionEvaluatorTests.cs @@ -272,13 +272,6 @@ namespace Spring.Expressions #endregion Serialization Tests - [Test(Description = "SPRNET-1381")] - public void TestShortcircuitAndOperator() - { - object boolean = ExpressionEvaluator.GetValue(new Inventor(), "Name != null and Name.Length == 0"); - Assert.AreEqual(false, boolean); - } - [Test] public void TestBitwiseXOR() { diff --git a/test/Spring/Spring.Core.Tests/Expressions/OpANDTests.cs b/test/Spring/Spring.Core.Tests/Expressions/OpANDTests.cs index 53e5550a..568ad6d5 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/OpANDTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/OpANDTests.cs @@ -1,19 +1,19 @@ #region License -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #endregion @@ -23,6 +23,7 @@ using NUnit.Framework; namespace Spring.Expressions { /// + /// Unit tests for the OpAND class. /// /// Erich Eichinger [TestFixture] @@ -34,5 +35,22 @@ namespace Spring.Expressions OpAND band = new OpAND(new IntLiteralNode("2"), new IntLiteralNode("3")); Assert.AreEqual( 2 & 3, band.GetValue(null,null) ); } + + [Test] + public void AndsBooleans() + { + OpAND band1 = new OpAND(new BooleanLiteralNode("true"), new BooleanLiteralNode("true")); + Assert.AreEqual(true, band1.GetValue(null, null)); + + OpAND band2 = new OpAND(new BooleanLiteralNode("true"), new BooleanLiteralNode("false")); + Assert.AreEqual(false, band2.GetValue(null, null)); + } + + [Test(Description = "SPRNET-1381")] + public void TestShortcircuitAndOperator() + { + object boolean = ExpressionEvaluator.GetValue(new Inventor(), "Name != null and Name.Length == 0"); + Assert.AreEqual(false, boolean); + } } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Expressions/OpORTests.cs b/test/Spring/Spring.Core.Tests/Expressions/OpORTests.cs index 7b2aaae3..3512692c 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/OpORTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/OpORTests.cs @@ -1,19 +1,19 @@ #region License -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #endregion @@ -24,6 +24,7 @@ using NUnit.Framework; namespace Spring.Expressions { /// + /// Unit tests for the OpOR class. /// /// Erich Eichinger [TestFixture] @@ -42,5 +43,12 @@ namespace Spring.Expressions OpOR bor = new OpOR(new BooleanLiteralNode("false"), new BooleanLiteralNode("true")); Assert.AreEqual(false || true , bor.GetValue(null, null)); } + + [Test(Description = "SPRNET-1381")] + public void TestShortcircuitOrOperator() + { + object boolean = ExpressionEvaluator.GetValue(new Inventor(), "Name == null or Name.Length == 0"); + Assert.AreEqual(true, boolean); + } } } \ No newline at end of file diff --git a/test/Spring/Spring.Core.Tests/Expressions/OpXORTests.cs b/test/Spring/Spring.Core.Tests/Expressions/OpXORTests.cs index f4eb948e..6c387b96 100644 --- a/test/Spring/Spring.Core.Tests/Expressions/OpXORTests.cs +++ b/test/Spring/Spring.Core.Tests/Expressions/OpXORTests.cs @@ -1,19 +1,19 @@ #region License -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #endregion @@ -23,6 +23,7 @@ using NUnit.Framework; namespace Spring.Expressions { /// + /// Unit tests for the OpXOR class. /// /// Erich Eichinger [TestFixture] @@ -33,8 +34,16 @@ namespace Spring.Expressions { OpXOR bxor = new OpXOR(new IntLiteralNode("2"), new IntLiteralNode("3")); Assert.AreEqual(2 ^ 3, bxor.GetValue(null, null)); - bxor = new OpXOR(new BooleanLiteralNode("true"), new BooleanLiteralNode("false")); - Assert.AreEqual(true ^ false, bxor.GetValue(null, null)); + } + + [Test] + public void XorsBooleans() + { + OpXOR bxor1 = new OpXOR(new BooleanLiteralNode("true"), new BooleanLiteralNode("false")); + Assert.AreEqual(true ^ false, bxor1.GetValue(null, null)); + + OpXOR bxor2 = new OpXOR(new BooleanLiteralNode("true"), new BooleanLiteralNode("true")); + Assert.AreEqual(true ^ true, bxor2.GetValue(null, null)); } } } \ No newline at end of file