/*
 * Copyright (C) 2017 The Flogger 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.
 */

package com.google.common.flogger.parser;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;

import com.google.common.flogger.backend.FormatOptions;
import com.google.common.flogger.backend.TemplateContext;
import com.google.common.flogger.parameter.Parameter;
import com.google.common.flogger.parameter.ParameterVisitor;
import java.util.ArrayList;
import java.util.List;

/** Utilities for testing base parser implementations. */
public final class ParserTestUtil {
  /**
   * A fake parameter that collects strings generated by the fake parser. Instances of this are
   * generated by parsers during testing to capture the state of the parse when a parameter is
   * processed.
   */
  static class FakeParameter extends Parameter {
    private final String details;

    FakeParameter(int index, String details) {
      super(FormatOptions.getDefault(), index);
      this.details = details;
    }

    @Override
    protected void accept(ParameterVisitor visitor, Object value) {
      throw new UnsupportedOperationException("not used in test");
    }

    @Override
    public String getFormat() {
      throw new UnsupportedOperationException("not used in test");
    }

    @Override
    public String toString() {
      return details.isEmpty() ? String.valueOf(getIndex()) : getIndex() + ":" + details;
    }
  }

  /** A message build that returns captured detail strings from the fake parser. */
  private static class FakeMessageBuilder extends MessageBuilder<List<String>> {
    private final List<String> details = new ArrayList<>();

    FakeMessageBuilder(MessageParser fakeParser, String message) {
      super(new TemplateContext(fakeParser, message));
    }

    @Override
    protected void addParameterImpl(int termStart, int termEnd, Parameter param) {
      details.add(param.toString());
    }

    @Override
    protected List<String> buildImpl() {
      return details;
    }
  }

  /**
   * Asserts that for a format message, the given parser will emit fake parameters with the
   * specified detail strings (in the given order).
   */
  static void assertParse(MessageParser fakeParser, String message, String... terms) {
    FakeMessageBuilder builder = new FakeMessageBuilder(fakeParser, message);
    // TODO(b/18153623): Remove the ugly Object[] cast
    assertThat(builder.build()).containsExactly((Object[]) terms).inOrder();
  }

  /**
   * Asserts that for a format message, the given parser will produce a parse error with the
   * given snippet in its message.
   */
  static void assertParseError(MessageParser fakeParser, String message, String errorPart) {
    try {
      new FakeMessageBuilder(fakeParser, message).build();
      fail("expected ParseException");
    } catch (ParseException expected) {
      assertThat(expected.getMessage()).contains(errorPart);
    }
  }
}
