From 8f3f4dfb2a32be014af9522e859d3014dd798ea5 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Mon, 17 Sep 2012 13:53:44 +0000 Subject: [PATCH] Add unit tests for varargs --- src/core/org/luaj/vm2/LuaValue.java | 4 +- src/core/org/luaj/vm2/TailcallVarargs.java | 9 + src/core/org/luaj/vm2/Varargs.java | 43 +++-- test/junit/org/luaj/vm2/AllTests.java | 1 + test/junit/org/luaj/vm2/VarargsTest.java | 197 +++++++++++++++++++++ 5 files changed, 240 insertions(+), 14 deletions(-) create mode 100644 test/junit/org/luaj/vm2/VarargsTest.java diff --git a/src/core/org/luaj/vm2/LuaValue.java b/src/core/org/luaj/vm2/LuaValue.java index 2cec897b..d32c288a 100644 --- a/src/core/org/luaj/vm2/LuaValue.java +++ b/src/core/org/luaj/vm2/LuaValue.java @@ -3532,7 +3532,7 @@ public class LuaValue extends Varargs { public int narg() { return 0; } public LuaValue arg1() { return NIL; } public String tojstring() { return "none"; } - public Varargs subargs(final int start) { return this; } + public Varargs subargs(final int start) { return start > 0? this: argerror(1, "start must be > 0"); } } @@ -3546,7 +3546,7 @@ public class LuaValue extends Varargs { return this; if (start > 1) return NONE; - return new Varargs.SubVarargs(this, start, 1); + return argerror(1, "start must be > 0"); } } diff --git a/src/core/org/luaj/vm2/TailcallVarargs.java b/src/core/org/luaj/vm2/TailcallVarargs.java index 5cffed4a..0b5d5254 100644 --- a/src/core/org/luaj/vm2/TailcallVarargs.java +++ b/src/core/org/luaj/vm2/TailcallVarargs.java @@ -21,6 +21,9 @@ ******************************************************************************/ package org.luaj.vm2; +import org.luaj.vm2.Varargs.ArrayPartVarargs; +import org.luaj.vm2.Varargs.PairVarargs; + /** * Subclass of {@link Varargs} that represents a lua tail call * in a Java library function execution environment. @@ -94,4 +97,10 @@ public class TailcallVarargs extends Varargs { eval(); return result.narg(); } + + public Varargs subargs(int start) { + if (result == null) + eval(); + return result.subargs(start); + } } \ No newline at end of file diff --git a/src/core/org/luaj/vm2/Varargs.java b/src/core/org/luaj/vm2/Varargs.java index 15ce8dce..30cb411f 100644 --- a/src/core/org/luaj/vm2/Varargs.java +++ b/src/core/org/luaj/vm2/Varargs.java @@ -501,14 +501,7 @@ public abstract class Varargs { * @param start the index from which to include arguments, where 1 is the first argument. * @return Varargs containing argument { start, start+1, ... , narg-start-1 } */ - public Varargs subargs(final int start) { - int end = narg(); - switch ( end-start ) { - case 0: return arg(start); - case 1: return new Varargs.PairVarargs(arg(start),arg(end)); - } - return end 2) return v2.subargs(start - 1); - return new SubVarargs(this, start, 2); + return LuaValue.argerror(1, "start must be > 0"); } } @@ -618,12 +611,25 @@ public abstract class Varargs { throw new IllegalArgumentException("nulls in array"); } public LuaValue arg(int i) { - return i >=1 && i<=v.length? v[i - 1]: r.arg(i-v.length); + return i < 1 ? LuaValue.NIL: i <= v.length? v[i - 1]: r.arg(i-v.length); } public int narg() { return v.length+r.narg(); } public LuaValue arg1() { return v.length>0? v[0]: r.arg1(); } + public Varargs subargs(int start) { + if (start <= 0) + LuaValue.argerror(1, "start must be > 0"); + if (start == 1) + return this; + if (start > v.length) + return LuaValue.NONE; + if (start == v.length) + return v[v.length - 1]; + if (start == v.length - 1) + return new PairVarargs(v[v.length - 2], v[v.length - 1]); + return new ArrayPartVarargs(v, start - 1, v.length - (start - 1)); + } } /** Varargs implemenation backed by an array of LuaValues @@ -665,8 +671,8 @@ public abstract class Varargs { this.length = length; this.more = more; } - public LuaValue arg(int i) { - return i>=1&&i<=length? v[i+offset-1]: more.arg(i-length); + public LuaValue arg(final int i) { + return i < 1? LuaValue.NIL: i <= length? v[offset+i-1]: more.arg(i-length); } public int narg() { return length + more.narg(); @@ -674,5 +680,18 @@ public abstract class Varargs { public LuaValue arg1() { return length>0? v[offset]: more.arg1(); } + public Varargs subargs(int start) { + if (start <= 0) + LuaValue.argerror(1, "start must be > 0"); + if (start == 1) + return this; + if (start > length) + return LuaValue.NONE; + if (start == length) + return v[offset + length - 1]; + if (start == length - 1) + return new PairVarargs(v[offset + length - 2], v[offset + length - 1]); + return new ArrayPartVarargs(v, offset + start - 1, length - (start - 1)); + } } } diff --git a/test/junit/org/luaj/vm2/AllTests.java b/test/junit/org/luaj/vm2/AllTests.java index 0b9da872..1abf3cb5 100644 --- a/test/junit/org/luaj/vm2/AllTests.java +++ b/test/junit/org/luaj/vm2/AllTests.java @@ -49,6 +49,7 @@ public class AllTests { vm.addTestSuite(LuaOperationsTest.class); vm.addTestSuite(StringTest.class); vm.addTestSuite(OrphanedThreadTest.class); + vm.addTestSuite(VarargsTest.class); suite.addTest(vm); // table tests diff --git a/test/junit/org/luaj/vm2/VarargsTest.java b/test/junit/org/luaj/vm2/VarargsTest.java new file mode 100644 index 00000000..87ad374c --- /dev/null +++ b/test/junit/org/luaj/vm2/VarargsTest.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2012 Luaj.org. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ +package org.luaj.vm2; + +import junit.framework.TestCase; + +/** + * Tests of basic unary and binary operators on main value types. + */ +public class VarargsTest extends TestCase { + + static LuaValue A = LuaValue.valueOf("a"); + static LuaValue B = LuaValue.valueOf("b"); + static LuaValue C = LuaValue.valueOf("c"); + static LuaValue D = LuaValue.valueOf("d"); + static LuaValue E = LuaValue.valueOf("e"); + static LuaValue F = LuaValue.valueOf("f"); + static LuaValue G = LuaValue.valueOf("g"); + static LuaValue H = LuaValue.valueOf("h"); + static LuaValue Z = LuaValue.valueOf("z"); + static LuaValue NIL = LuaValue.NIL; + static Varargs A_G = LuaValue.varargsOf(new LuaValue[] { A, B, C, D, E, F, G }); + static Varargs B_E = LuaValue.varargsOf(new LuaValue[] { B, C, D, E }); + static Varargs C_G = LuaValue.varargsOf(new LuaValue[] { C, D, E, F, G }); + static Varargs C_E = LuaValue.varargsOf(new LuaValue[] { C, D, E }); + static Varargs DE = LuaValue.varargsOf(new LuaValue[] { D, E }); + static Varargs E_G = LuaValue.varargsOf(new LuaValue[] { E, F, G }); + static Varargs FG = LuaValue.varargsOf(new LuaValue[] { F, G }); + static LuaValue[] Z_H_array = {Z, A, B, C, D, E, F, G, H }; + static Varargs A_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 1, 7); + static Varargs B_E_alt = new Varargs.ArrayPartVarargs(Z_H_array, 2, 4); + static Varargs C_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 3, 5); + static Varargs C_E_alt = new Varargs.ArrayPartVarargs(Z_H_array, 3, 3); + static Varargs C_E_alt2 = LuaValue.varargsOf(C, D, E); + static Varargs DE_alt = new Varargs.PairVarargs(D,E); + static Varargs DE_alt2 = LuaValue.varargsOf(D,E); + static Varargs E_G_alt = new Varargs.ArrayPartVarargs(Z_H_array, 5, 3); + static Varargs FG_alt = new Varargs.PairVarargs(F, G); + static Varargs NONE = LuaValue.NONE; + + static void expectEquals(Varargs x, Varargs y) { + assertEquals(x.narg(), y.narg()); + assertEquals(x.arg1(), y.arg1()); + assertEquals(x.arg(0), y.arg(0)); + assertEquals(x.arg(-1), y.arg(-1)); + assertEquals(x.arg(2), y.arg(2)); + assertEquals(x.arg(3), y.arg(3)); + for (int i = 4; i < x.narg() + 2; ++i) + assertEquals(x.arg(i), y.arg(i)); + } + + public void testSanity() { + expectEquals(A_G, A_G); + expectEquals(A_G_alt, A_G_alt); + expectEquals(A_G, A_G_alt); + expectEquals(B_E, B_E_alt); + expectEquals(C_G, C_G_alt); + expectEquals(C_E, C_E_alt); + expectEquals(C_E, C_E_alt2); + expectEquals(DE, DE_alt); + expectEquals(DE, DE_alt2); + expectEquals(E_G, E_G_alt); + expectEquals(FG, FG_alt); + expectEquals(FG_alt, FG_alt); + expectEquals(A, A); + expectEquals(NONE, NONE); + expectEquals(NIL, NIL); + } + + public void testNegativeIndices() { + expectNegSubargsError(A_G); + expectNegSubargsError(A_G_alt); + expectNegSubargsError(B_E); + expectNegSubargsError(B_E_alt); + expectNegSubargsError(C_G); + expectNegSubargsError(C_G_alt); + expectNegSubargsError(C_E); + expectNegSubargsError(C_E_alt); + expectNegSubargsError(C_E_alt2); + expectNegSubargsError(DE); + expectNegSubargsError(DE_alt); + expectNegSubargsError(DE_alt2); + expectNegSubargsError(E_G); + expectNegSubargsError(FG); + expectNegSubargsError(A); + expectNegSubargsError(NONE); + expectNegSubargsError(NIL); + } + + public void testVarargsSubargs() { + expectEquals(A_G, A_G.subargs(1)); + expectEquals(A_G, A_G_alt.subargs(1)); + expectEquals(C_G, A_G.subargs(3)); + expectEquals(C_G, A_G_alt.subargs(3)); + expectEquals(C_G, A_G.subargs(3).subargs(1)); + expectEquals(C_G, A_G_alt.subargs(3).subargs(1)); + expectEquals(E_G, A_G.subargs(5)); + expectEquals(E_G, A_G_alt.subargs(5)); + expectEquals(E_G, A_G.subargs(5).subargs(1)); + expectEquals(E_G, A_G_alt.subargs(5).subargs(1)); + expectEquals(FG, A_G.subargs(6)); + expectEquals(FG, A_G_alt.subargs(6)); + expectEquals(FG, A_G.subargs(6).subargs(1)); + expectEquals(FG, A_G_alt.subargs(6).subargs(1)); + expectEquals(G, A_G.subargs(7)); + expectEquals(G, A_G_alt.subargs(7)); + expectEquals(G, A_G.subargs(7).subargs(1)); + expectEquals(G, A_G_alt.subargs(7).subargs(1)); + expectEquals(NONE, A_G.subargs(8)); + expectEquals(NONE, A_G_alt.subargs(8)); + expectEquals(NONE, A_G.subargs(8).subargs(1)); + expectEquals(NONE, A_G_alt.subargs(8).subargs(1)); + + expectEquals(C_G, C_G.subargs(1)); + expectEquals(C_G, C_G_alt.subargs(1)); + expectEquals(E_G, C_G.subargs(3)); + expectEquals(E_G, C_G_alt.subargs(3)); + expectEquals(E_G, C_G.subargs(3).subargs(1)); + expectEquals(E_G, C_G_alt.subargs(3).subargs(1)); + expectEquals(FG, C_G.subargs(4)); + expectEquals(FG, C_G_alt.subargs(4)); + expectEquals(FG, C_G.subargs(4).subargs(1)); + expectEquals(FG, C_G_alt.subargs(4).subargs(1)); + expectEquals(G, C_G.subargs(5)); + expectEquals(G, C_G_alt.subargs(5)); + expectEquals(G, C_G.subargs(5).subargs(1)); + expectEquals(G, C_G_alt.subargs(5).subargs(1)); + expectEquals(NONE, C_G.subargs(6)); + expectEquals(NONE, C_G_alt.subargs(6)); + expectEquals(NONE, C_G.subargs(6).subargs(1)); + expectEquals(NONE, C_G_alt.subargs(6).subargs(1)); + + expectEquals(E_G, E_G.subargs(1)); + expectEquals(E_G, E_G_alt.subargs(1)); + expectEquals(FG, E_G.subargs(2)); + expectEquals(FG, E_G_alt.subargs(2)); + expectEquals(FG, E_G.subargs(2).subargs(1)); + expectEquals(FG, E_G_alt.subargs(2).subargs(1)); + expectEquals(G, E_G.subargs(3)); + expectEquals(G, E_G_alt.subargs(3)); + expectEquals(G, E_G.subargs(3).subargs(1)); + expectEquals(G, E_G_alt.subargs(3).subargs(1)); + expectEquals(NONE, E_G.subargs(4)); + expectEquals(NONE, E_G_alt.subargs(4)); + expectEquals(NONE, E_G.subargs(4).subargs(1)); + expectEquals(NONE, E_G_alt.subargs(4).subargs(1)); + + expectEquals(FG, FG.subargs(1)); + expectEquals(FG, FG_alt.subargs(1)); + expectEquals(G, FG.subargs(2)); + expectEquals(G, FG_alt.subargs(2)); + expectEquals(G, FG.subargs(2).subargs(1)); + expectEquals(G, FG_alt.subargs(2).subargs(1)); + expectEquals(NONE, FG.subargs(3)); + expectEquals(NONE, FG_alt.subargs(3)); + expectEquals(NONE, FG.subargs(3).subargs(1)); + expectEquals(NONE, FG_alt.subargs(3).subargs(1)); + + expectEquals(NONE, NONE.subargs(1)); + expectEquals(NONE, NONE.subargs(2)); + } + + static void expectNegSubargsError(Varargs v) { + String expected_msg = "bad argument #1: start must be > 0"; + try { + v.subargs(0); + fail("Failed to throw exception for index 0"); + } catch ( LuaError e ) { + assertEquals(expected_msg, e.getMessage()); + } + try { + v.subargs(-1); + fail("Failed to throw exception for index -1"); + } catch ( LuaError e ) { + assertEquals(expected_msg, e.getMessage()); + } + } +}