Test.java

/***************************************************************************
   Copyright 2015 Emily Estes

   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.
***************************************************************************/
package net.metanotion.sqltest;


import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.metanotion.sqlc.SQLObjectServer;

interface Test {
	public void eval(Connection conn, SQLObjectServer os, Map<String,Value> env) throws Exception;
}

final class Let implements Test {
	private static final Logger logger = LoggerFactory.getLogger(Let.class);
	private final String name;
	private final GenerateValue expr;

	public Let(final String name, final GenerateValue expr) {
		this.name = name;
		this.expr = expr;
	}

	public static Value convert(final Object val) {
		logger.debug("Converting a {}", val);
		if(val instanceof Iterable) {
			final Iterable valueList = (Iterable) val;
			final ArrayList<Value> list = new ArrayList<>();
			for(final Object o: valueList) { list.add(convert(o)); }
			return new ListValue(list);
		} else if (val instanceof Map) {
			final Map<Object,Object> valueMap = (Map<Object,Object>) val;
			final HashMap<String,Value> map = new HashMap<>();
			for(final Map.Entry<Object,Object> e: valueMap.entrySet()) {
				map.put(e.getKey().toString(), convert(e.getValue()));
			}
			return new RowValue(map);
		} else if (val instanceof Number) {
			final Number num = (Number) val;
			return new NumberValue(num);
		} else if (val instanceof Boolean) {
			final Boolean bool = (Boolean) val;
			return new BooleanValue(bool);
		} else if (val instanceof String) {
			return new StringValue(val.toString());
		} else if (val == null) {
			return NullValue.INSTANCE;
		} else {
			return new ObjectValue(val);
		}
	}

	@Override public void eval(final Connection conn, final SQLObjectServer os, final Map<String,Value> env) throws Exception {
		logger.debug("Evaluating {}", name);
		env.put(name, convert(expr.eval(conn, os, env)));
	}
}

final class Exec implements Test {
	private static final Logger logger = LoggerFactory.getLogger(Exec.class);
	private final GenerateValue expr;
	public Exec(final GenerateValue expr) { this.expr = expr; }
	@Override public void eval(final Connection conn, final SQLObjectServer os, final Map<String,Value> env) throws Exception {
		logger.debug("Executing");
		expr.eval(conn, os, env);
	}
}

final class Check implements Test {
	private static final Logger logger = LoggerFactory.getLogger(Check.class);

	private final int line;
	private final GenerateValue expr;
	private final Value expected;

	public Check(final int line, final GenerateValue expr, final Value expected) {
		logger.debug("Expected {}", expected.getClass());
		this.line = line;
		this.expr = expr;
		this.expected = expected;
	}

	@Override public void eval(final Connection conn, final SQLObjectServer os, final Map<String,Value> env) {
		logger.debug("Verifying {}", line);
		Object result = null;
		try {
			result = expr.eval(conn, os, env);
		} catch (final Exception ex) {
			result = ex;
		}
		if(!expected.compare(result, env)) {
			logger.debug("At line {}\nExpected:\n{}\ninstead of:\n{}\n", line, expected, result);
			throw new RuntimeException("Unexpected result at line " + line);
		}
	}
}