package org.luaj.vm2;

import java.io.StringReader;

import org.luaj.vm2.libs.jse.JsePlatform;

public final class Lua54SmokeTestMain {
	private static void check(String name, Varargs actual, LuaValue... expected) {
		if (actual.narg() != expected.length) {
			throw new IllegalStateException(name + " expected " + expected.length + " values but got " + actual.narg() + ": " + actual);
		}
		for (int i = 0; i < expected.length; i++) {
			LuaValue value = actual.arg(i + 1);
			if (!value.eq_b(expected[i])) {
				throw new IllegalStateException(name + " mismatch at #" + (i + 1) + ": expected " + expected[i] + " but got " + value);
			}
		}
		System.out.println("ok  " + name + " -> " + actual);
	}

	private static Varargs run(String name, String script) throws Exception {
		Globals globals = JsePlatform.debugGlobals();
		return globals.load(new StringReader(script), name).invoke();
	}

	private static void checkCompileError(String name, String script, String expectedMessagePart) throws Exception {
		Globals globals = JsePlatform.debugGlobals();
		try {
			globals.load(new StringReader(script), name);
			throw new IllegalStateException(name + " expected compile error containing: " + expectedMessagePart);
		} catch (LuaError e) {
			if (e.getMessage() == null || e.getMessage().indexOf(expectedMessagePart) < 0) {
				throw new IllegalStateException(name + " unexpected compile error: " + e.getMessage(), e);
			}
			System.out.println("ok  " + name + " -> " + e.getMessage());
		}
	}

	public static void main(String[] args) throws Exception {
		check(
			"bit32_absent",
			run("bit32_absent", "return bit32 == nil\n"),
			LuaValue.TRUE);

		check(
			"randomseed_54",
			run("randomseed_54",
				"local a, b = math.randomseed(11, 22)\n" +
				"local x1, x2 = math.random(), math.random(1, 1000000)\n" +
				"math.randomseed(11, 22)\n" +
				"local y1, y2 = math.random(), math.random(1, 1000000)\n" +
				"return a, b, x1 == y1 and x2 == y2\n"),
			LuaValue.valueOf(11),
			LuaValue.valueOf(22),
			LuaValue.TRUE);

		check(
			"randomseed_auto",
			run("randomseed_auto",
				"local a, b = math.randomseed()\n" +
				"return math.type(a), math.type(b)\n"),
			LuaValue.valueOf("integer"),
			LuaValue.valueOf("integer"));

		checkCompileError(
			"const_local",
			"local x <const> = 1\nx = 2\n",
			"const variable");

		checkCompileError(
			"const_upvalue",
			"local x <const> = 1\nreturn function() x = 2 end\n",
			"const variable");

		check(
			"close_scope",
			run("close_scope",
				"local mt = { __close = function(self, err) _G.marker = err or 'closed' end }\n" +
				"do local h <close> = setmetatable({}, mt) end\n" +
				"return marker\n"),
			LuaValue.valueOf("closed"));

		check(
			"close_non_closable",
			run("close_non_closable",
				"local ok, err = pcall(function()\n" +
				"  local x <close> = {}\n" +
				"end)\n" +
				"return ok, string.find(err, 'non-closable', 1, true) ~= nil\n"),
			LuaValue.FALSE,
			LuaValue.TRUE);

		check(
			"warn_control",
			run("warn_control",
				"warn('@off')\n" +
				"warn('hidden')\n" +
				"warn('@on')\n" +
				"return 1\n"),
			LuaValue.valueOf(1));

		check(
			"coroutine_running",
			run("coroutine_running",
				"local mainThread, isMain = coroutine.running()\n" +
				"local co = coroutine.create(function()\n" +
				"  local childThread, childMain = coroutine.running()\n" +
				"  return type(childThread), childMain\n" +
				"end)\n" +
				"local ok, childType, childMain = coroutine.resume(co)\n" +
				"return type(mainThread), isMain, ok and childType == 'thread' and childMain == false\n"),
			LuaValue.valueOf("thread"),
			LuaValue.TRUE,
			LuaValue.TRUE);

		check(
			"coroutine_close",
			run("coroutine_close",
				"local co = coroutine.create(function() coroutine.yield('pause') end)\n" +
				"coroutine.resume(co)\n" +
				"local ok = coroutine.close(co)\n" +
				"return ok, coroutine.status(co)\n"),
			LuaValue.TRUE,
			LuaValue.valueOf("dead"));

		check(
			"unicode_escape",
			run("unicode_escape",
				"local s = '\\u{E4}\\u{1F642}'\n" +
				"return #s, string.byte(s, 1, #s)\n"),
			LuaValue.valueOf(6),
			LuaValue.valueOf(195),
			LuaValue.valueOf(164),
			LuaValue.valueOf(240),
			LuaValue.valueOf(159),
			LuaValue.valueOf(153),
			LuaValue.valueOf(130));

		check(
			"dump_roundtrip_54",
			run("dump_roundtrip_54",
				"local dumped = string.dump(function()\n" +
				"  local mt = { __close = function(self, err) _G.marker = err or 'closed' end }\n" +
				"  do local h <close> = setmetatable({}, mt) end\n" +
				"  return marker\n" +
				"end)\n" +
				"local loaded = assert(load(dumped, 'dumped', 'b'))\n" +
				"return loaded()\n"),
			LuaValue.valueOf("closed"));
	}
}
