001/*
002 * Copyright (C) 2022 - 2024, the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *    http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.github.ascopes.jct.assertions;
017
018import static java.util.Objects.requireNonNull;
019import static org.assertj.core.api.Assertions.assertThat;
020
021import io.github.ascopes.jct.diagnostics.TraceDiagnostic;
022import io.github.ascopes.jct.repr.TraceDiagnosticRepresentation;
023import java.util.Locale;
024import javax.tools.JavaFileObject;
025import org.assertj.core.api.AbstractAssert;
026import org.assertj.core.api.AbstractInstantAssert;
027import org.assertj.core.api.AbstractLongAssert;
028import org.assertj.core.api.AbstractStringAssert;
029import org.jspecify.annotations.Nullable;
030
031/**
032 * Assertions for an individual {@link TraceDiagnostic trace diagnostic}.
033 *
034 * @author Ashley Scopes
035 * @since 0.0.1
036 */
037public final class TraceDiagnosticAssert
038    extends AbstractAssert<TraceDiagnosticAssert, TraceDiagnostic<? extends JavaFileObject>> {
039
040  /**
041   * Initialize this assertion type.
042   *
043   * @param value the value to assert on.
044   */
045  @SuppressWarnings("DataFlowIssue")
046  public TraceDiagnosticAssert(@Nullable TraceDiagnostic<? extends JavaFileObject> value) {
047    super(value, TraceDiagnosticAssert.class);
048    info.useRepresentation(TraceDiagnosticRepresentation.getInstance());
049  }
050
051  /**
052   * Get assertions for the kind of the diagnostic.
053   *
054   * @return the assertions for the diagnostic kind.
055   * @throws AssertionError if the diagnostic is null.
056   */
057  public DiagnosticKindAssert kind() {
058    isNotNull();
059
060    return new DiagnosticKindAssert(actual.getKind());
061  }
062
063  /**
064   * Get assertions for the source of the diagnostic.
065   *
066   * <p>If no source is present, then the value in the returned assertions may be {@code null}.
067   *
068   * @return the assertions for the source of the diagnostic.
069   * @throws AssertionError if the diagnostic is null.
070   */
071  public JavaFileObjectAssert source() {
072    isNotNull();
073
074    return new JavaFileObjectAssert(actual.getSource());
075  }
076
077  /**
078   * Get assertions for the position of the diagnostic.
079   *
080   * <p>The value may be -1 if no information is available.
081   *
082   * @return the assertions for the position of the diagnostic.
083   * @throws AssertionError if the diagnostic is null.
084   */
085  public AbstractLongAssert<?> position() {
086    isNotNull();
087
088    return assertThat(actual.getPosition()).describedAs("position");
089  }
090
091  /**
092   * Get assertions for the start position of the diagnostic.
093   *
094   * <p>The value may be -1 if no information is available.
095   *
096   * @return the assertions for the start position of the diagnostic.
097   * @throws AssertionError if the diagnostic is null.
098   */
099  public AbstractLongAssert<?> startPosition() {
100    isNotNull();
101
102    return assertThat(actual.getStartPosition()).describedAs("start position");
103  }
104
105  /**
106   * Get assertions for the end position of the diagnostic.
107   *
108   * <p>The value may be -1 if no information is available.
109   *
110   * @return the assertions for the end position of the diagnostic.
111   * @throws AssertionError if the diagnostic is null.
112   */
113  public AbstractLongAssert<?> endPosition() {
114    isNotNull();
115
116    return assertThat(actual.getEndPosition()).describedAs("end position");
117  }
118
119  /**
120   * Get assertions for the line number of the diagnostic.
121   *
122   * <p>The value may be -1 if no information is available.
123   *
124   * @return the assertions for the line number of the diagnostic.
125   * @throws AssertionError if the diagnostic is null.
126   */
127  public AbstractLongAssert<?> lineNumber() {
128    isNotNull();
129
130    return assertThat(actual.getLineNumber()).describedAs("line number");
131  }
132
133  /**
134   * Get assertions for the column number of the diagnostic.
135   *
136   * <p>The value may be -1 if no information is available.
137   *
138   * @return the assertions for the column number of the diagnostic.
139   * @throws AssertionError if the diagnostic is null.
140   */
141  public AbstractLongAssert<?> columnNumber() {
142    isNotNull();
143
144    return assertThat(actual.getColumnNumber()).describedAs("column number");
145  }
146
147  /**
148   * Get assertions for the code of the diagnostic.
149   *
150   * @return the assertions for the code of the diagnostic.
151   * @throws AssertionError if the diagnostic is null.
152   */
153  public AbstractStringAssert<?> code() {
154    isNotNull();
155
156    return assertThat(actual.getCode()).describedAs("code");
157  }
158
159  /**
160   * Get assertions for the message of the diagnostic, assuming the default locale.
161   *
162   * @return the assertions for the message of the diagnostic.
163   * @throws AssertionError if the diagnostic is null.
164   */
165  public AbstractStringAssert<?> message() {
166    isNotNull();
167
168    return assertThat(actual.getMessage(null));
169  }
170
171  /**
172   * Get assertions for the message of the diagnostic.
173   *
174   * @param locale the locale to use.
175   * @return the assertions for the message of the diagnostic.
176   * @throws AssertionError if the diagnostic is null.
177   */
178  public AbstractStringAssert<?> message(Locale locale) {
179    requireNonNull(locale, "locale must not be null");
180
181    isNotNull();
182
183    return assertThat(actual.getMessage(locale));
184  }
185
186  /**
187   * Get assertions for the timestamp of the diagnostic.
188   *
189   * @return the assertions for the timestamp of the diagnostic.
190   * @throws AssertionError if the diagnostic is null.
191   */
192  public AbstractInstantAssert<?> timestamp() {
193    isNotNull();
194
195    return assertThat(actual.getTimestamp());
196  }
197
198  /**
199   * Get assertions for the thread ID of the thread that reported the diagnostic to the compiler.
200   *
201   * @return the assertions for the thread ID.
202   * @throws AssertionError if the diagnostic is null.
203   */
204  public AbstractLongAssert<?> threadId() {
205    isNotNull();
206
207    return assertThat(actual.getThreadId());
208  }
209
210  /**
211   * Get assertions for the thread name of the thread that reported the diagnostic.
212   *
213   * <p>This may not be present in some situations, in which case the returned assertions will be
214   * performed on a null value instead.
215   *
216   * @return the assertions for the thread name.
217   * @throws AssertionError if the diagnostic is null.
218   */
219  public AbstractStringAssert<?> threadName() {
220    isNotNull();
221
222    return assertThat(actual.getThreadName());
223  }
224
225  /**
226   * Get assertions for the stack trace of the location the diagnostic was reported to.
227   *
228   * @return the assertions for the stack trace.
229   * @throws AssertionError if the diagnostic is null.
230   */
231  public StackTraceAssert stackTrace() {
232    isNotNull();
233
234    return new StackTraceAssert(actual.getStackTrace());
235  }
236}