Package com.asakusafw.testdriver.excel

Source Code of com.asakusafw.testdriver.excel.ExcelSheetRuleProvider

/**
* Copyright 2011-2014 Asakusa Framework Team.
*
* 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 com.asakusafw.testdriver.excel;

import static com.asakusafw.testdriver.rule.Predicates.*;

import java.io.IOException;
import java.net.URI;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.asakusafw.testdriver.core.DataModelDefinition;
import com.asakusafw.testdriver.core.PropertyType;
import com.asakusafw.testdriver.core.VerifyContext;
import com.asakusafw.testdriver.core.VerifyRule;
import com.asakusafw.testdriver.core.VerifyRuleProvider;
import com.asakusafw.testdriver.excel.legacy.LegacyExcelRuleExtractor;
import com.asakusafw.testdriver.rule.BothAreNull;
import com.asakusafw.testdriver.rule.DataModelCondition;
import com.asakusafw.testdriver.rule.Predicates;
import com.asakusafw.testdriver.rule.ValuePredicate;
import com.asakusafw.testdriver.rule.VerifyRuleBuilder;
import com.asakusafw.testdriver.rule.VerifyRuleBuilder.Property;

/**
* Provides {@link VerifyRule} from Excel Sheet.
* This accepts URI:
* <ul>
* <li> which is also a valid URL to obtain an Excel workbook, </li>
* <li> whose "path" segment ends with ".xls", or </li>
* <li>
*     whose "fragment" is "#:" + 0-origin sheet number, "#" + sheet name,
*     or null (which means the first sheet)
* </li>
* </ul>
* @since 0.2.0
*/
public class ExcelSheetRuleProvider implements VerifyRuleProvider {

    static final Logger LOG = LoggerFactory.getLogger(ExcelSheetRuleProvider.class);

    private static final List<ExcelRuleExtractor> EXTRACTORS;
    static {
        List<ExcelRuleExtractor> drivers = new ArrayList<ExcelRuleExtractor>();
        drivers.add(new DefaultExcelRuleExtractor());
        drivers.add(new LegacyExcelRuleExtractor());
        EXTRACTORS = Collections.unmodifiableList(drivers);
    }

    @Override
    public <T> VerifyRule get(
            DataModelDefinition<T> definition, VerifyContext context, URI source) throws IOException {
        Sheet sheet = Util.extract(source);
        if (sheet == null) {
            return null;
        }
        LOG.debug("Finding Excel sheet extractor: {}", source);
        ExcelRuleExtractor extractor = findExtractor(sheet);
        if (extractor == null) {
            LOG.debug("Valid Excel sheet extractor is not found: {}", source);
            return null;
        }
        LOG.info("Excelシートをテスト条件に利用します: {}", source);
        try {
            return resolve(definition, context, sheet, extractor);
        } catch (ExcelRuleExtractor.FormatException e) {
            throw new IOException(MessageFormat.format(
                    "{0}の形式が正しくありません",
                    source), e);
        }
    }

    private ExcelRuleExtractor findExtractor(Sheet sheet) {
        assert sheet != null;
        for (ExcelRuleExtractor extractor : EXTRACTORS) {
            if (extractor.supports(sheet)) {
                return extractor;
            }
        }
        return null;
    }

    private <T> VerifyRule resolve(
            DataModelDefinition<T> definition,
            VerifyContext context,
            Sheet sheet,
            ExcelRuleExtractor extractor) throws ExcelRuleExtractor.FormatException {
        assert definition != null;
        assert context != null;
        assert sheet != null;
        assert extractor != null;

        VerifyRuleBuilder builder = new VerifyRuleBuilder(definition);
        Set<DataModelCondition> modelPredicates = extractor.extractDataModelCondition(sheet);
        if (modelPredicates.contains(DataModelCondition.IGNORE_ABSENT)) {
            builder.acceptIfAbsent();
        }
        if (modelPredicates.contains(DataModelCondition.IGNORE_UNEXPECTED)) {
            builder.acceptIfUnexpected();
        }
        if (modelPredicates.contains(DataModelCondition.IGNORE_MATCHED) == false) {
            int start = extractor.extractPropertyRowStartIndex(sheet);
            int end = sheet.getLastRowNum() + 1;
            for (int i = start; i < end; i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    continue;
                }
                resolveRow(builder, definition, context, row, extractor);
            }
        }
        return builder.toVerifyRule();
    }

    private <T> void resolveRow(
            VerifyRuleBuilder builder,
            DataModelDefinition<T> definition,
            VerifyContext context,
            Row row,
            ExcelRuleExtractor extractor) throws ExcelRuleExtractor.FormatException {
        assert builder != null;
        assert definition != null;
        assert context != null;
        assert row != null;
        assert extractor != null;
        String name = extractor.extractName(row);
        if (name == null) {
            return;
        }
        VerifyRuleBuilder.Property property;
        try {
            property = builder.property(name);
        } catch (IllegalArgumentException e) {
            throw new ExcelRuleExtractor.FormatException(MessageFormat.format(
                    "プロパティが見つかりません (row={0})",
                    row.getRowNum() + 1), e);
        }
        ValueConditionKind value = extractor.extractValueCondition(row);
        NullityConditionKind nullity = extractor.extractNullityCondition(row);
        if (buildNullity(property, value, nullity) == false) {
            return;
        }
        String extraOptions = extractor.extractOptions(row);
        buildValue(property, context, value, extraOptions);
    }

    private boolean buildNullity(
            VerifyRuleBuilder.Property property,
            ValueConditionKind value,
            NullityConditionKind nullity) throws ExcelRuleExtractor.FormatException {
        assert property != null;
        assert value != null;
        assert nullity != null;
        switch (nullity) {
        case NORMAL:
            if (value == ValueConditionKind.EQUAL) {
                property.accept(new BothAreNull());
            }
            break;
        case ACCEPT_ABSENT:
            property.accept(isNull());
            break;
        case ACCEPT_PRESENT:
            property.accept(not(isNull()));
            break;
        case DENY_ABSENT:
            // must be denied if value was checked
            if (value == ValueConditionKind.ANY || value == ValueConditionKind.KEY) {
                property.accept(not(isNull()));
            }
            break;
        case DENY_PRESENT:
            // must be denied if value was checked
            property.accept(isNull());
            return false;
        default:
            throw new ExcelRuleExtractor.FormatException(MessageFormat.format(
                    "Unknown nullity constraint \"{1}\": {0}",
                    property,
                    nullity));
        }
        return true;
    }

    private void buildValue(
            VerifyRuleBuilder.Property property,
            VerifyContext context,
            ValueConditionKind value,
            String extraOptions) throws ExcelRuleExtractor.FormatException {
        assert property != null;
        assert context != null;
        assert value != null;
        switch (value) {
        case ANY:
            break;
        case KEY:
            property.asKey();
            break;
        case EQUAL:
            property.accept(Predicates.equals());
            break;
        case CONTAIN:
            if (property.getType() == PropertyType.STRING) {
                property.accept(containsString());
            } else {
                throw typeError(property, ValueConditionKind.CONTAIN);
            }
            break;
        case TODAY:
            if (property.getType() == PropertyType.DATE
                    || property.getType() == PropertyType.DATETIME) {
                property.accept(createTodayPredicate(context));
            } else {
                throw typeError(property, ValueConditionKind.TODAY);
            }
            break;
        case NOW:
            if (property.getType() == PropertyType.DATE
                    || property.getType() == PropertyType.DATETIME) {
                property.accept(createNowPredicate(context));
            } else {
                throw typeError(property, ValueConditionKind.NOW);
            }
            break;
        case EXPRESSION:
            buildExpression(property, context, extraOptions);
            break;
        default:
            throw new ExcelRuleExtractor.FormatException(MessageFormat.format(
                    "Unknown value constraint \"{1}\": {0}",
                    property,
                    value));
        }
    }

    private void buildExpression(
            VerifyRuleBuilder.Property property,
            VerifyContext context,
            String expression) throws ExcelRuleExtractor.FormatException {
        ExcelSheetRuleExtensionRepository repo = ExcelSheetRuleExtensionRepository.get(context);
        ValuePredicate<?> resolved = repo.resolve(context, property.getName(), property.getType(), expression);
        if (resolved != null) {
            property.accept(resolved);
        } else {
            throw new ExcelRuleExtractor.FormatException(MessageFormat.format(
                    "Unsupported optional expression: {0} -> \"{1}\"",
                    property.getName(),
                    expression));
        }
    }

    private ValuePredicate<Calendar> createTodayPredicate(VerifyContext context) {
        assert context != null;
        Calendar begin = toDate(context.getTestStarted());
        Calendar end = toDate(context.getTestFinished());
        end.add(Calendar.DATE, 1);
        end.add(Calendar.MILLISECOND, -1);
        return Predicates.period(begin, end);
    }

    private Calendar toDate(Date date) {
        assert date != null;
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        int y = instance.get(Calendar.YEAR);
        int m = instance.get(Calendar.MONTH);
        int d = instance.get(Calendar.DATE);
        instance.clear();
        instance.set(y, m, d);
        return instance;
    }

    private ValuePredicate<Calendar> createNowPredicate(VerifyContext context) {
        assert context != null;
        Calendar begin = toDatetime(context.getTestStarted());
        Calendar end = toDatetime(context.getTestFinished());
        end.add(Calendar.SECOND, 1);
        end.add(Calendar.MILLISECOND, -1);
        return Predicates.period(begin, end);
    }

    private Calendar toDatetime(Date date) {
        assert date != null;
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        int y = instance.get(Calendar.YEAR);
        int m = instance.get(Calendar.MONTH);
        int d = instance.get(Calendar.DATE);
        int ho = instance.get(Calendar.HOUR_OF_DAY);
        int mi = instance.get(Calendar.MINUTE);
        int se = instance.get(Calendar.SECOND);
        instance.clear();
        instance.set(y, m, d, ho, mi, se);
        return instance;
    }

    private ExcelRuleExtractor.FormatException typeError(Property property, ValueConditionKind kind) {
        assert property != null;
        assert kind != null;
        return new ExcelRuleExtractor.FormatException(MessageFormat.format(
                "{1}をプロパティ\"{0}\"に利用できません: {2}のみに利用可能です",
                property.getName(),
                kind.getTitle(),
                kind.getExpectedType()));
    }
}
TOP

Related Classes of com.asakusafw.testdriver.excel.ExcelSheetRuleProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.