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.apiguardian.api.API;
026import org.apiguardian.api.API.Status;
027import org.assertj.core.api.AbstractAssert;
028import org.assertj.core.api.AbstractInstantAssert;
029import org.assertj.core.api.AbstractLongAssert;
030import org.assertj.core.api.AbstractStringAssert;
031import org.jspecify.annotations.Nullable;
032
033/**
034 * Assertions for an individual {@link TraceDiagnostic trace diagnostic}.
035 *
036 * @author Ashley Scopes
037 * @since 0.0.1
038 */
039@API(since = "0.0.1", status = Status.STABLE)
040public final class TraceDiagnosticAssert
041    extends AbstractAssert<TraceDiagnosticAssert, TraceDiagnostic<? extends JavaFileObject>> {
042
043  /**
044   * Initialize this assertion type.
045   *
046   * @param value the value to assert on.
047   */
048  @SuppressWarnings("DataFlowIssue")
049  public TraceDiagnosticAssert(@Nullable TraceDiagnostic<? extends JavaFileObject> value) {
050    super(value, TraceDiagnosticAssert.class);
051    info.useRepresentation(TraceDiagnosticRepresentation.getInstance());
052  }
053
054  /**
055   * Get assertions for the kind of the diagnostic.
056   *
057   * @return the assertions for the diagnostic kind.
058   * @throws AssertionError if the diagnostic is null.
059   */
060  public DiagnosticKindAssert kind() {
061    isNotNull();
062
063    return new DiagnosticKindAssert(actual.getKind());
064  }
065
066  /**
067   * Get assertions for the source of the diagnostic.
068   *
069   * <p>If no source is present, then the value in the returned assertions may be {@code null}.
070   *
071   * @return the assertions for the source of the diagnostic.
072   * @throws AssertionError if the diagnostic is null.
073   */
074  public JavaFileObjectAssert source() {
075    isNotNull();
076
077    return new JavaFileObjectAssert(actual.getSource());
078  }
079
080  /**
081   * Get assertions for the position of the diagnostic.
082   *
083   * <p>The value may be -1 if no information is available.
084   *
085   * @return the assertions for the position of the diagnostic.
086   * @throws AssertionError if the diagnostic is null.
087   */
088  public AbstractLongAssert<?> position() {
089    isNotNull();
090
091    return assertThat(actual.getPosition()).describedAs("position");
092  }
093
094  /**
095   * Get assertions for the start position of the diagnostic.
096   *
097   * <p>The value may be -1 if no information is available.
098   *
099   * @return the assertions for the start position of the diagnostic.
100   * @throws AssertionError if the diagnostic is null.
101   */
102  public AbstractLongAssert<?> startPosition() {
103    isNotNull();
104
105    return assertThat(actual.getStartPosition()).describedAs("start position");
106  }
107
108  /**
109   * Get assertions for the end position of the diagnostic.
110   *
111   * <p>The value may be -1 if no information is available.
112   *
113   * @return the assertions for the end position of the diagnostic.
114   * @throws AssertionError if the diagnostic is null.
115   */
116  public AbstractLongAssert<?> endPosition() {
117    isNotNull();
118
119    return assertThat(actual.getEndPosition()).describedAs("end position");
120  }
121
122  /**
123   * Get assertions for the line number of the diagnostic.
124   *
125   * <p>The value may be -1 if no information is available.
126   *
127   * @return the assertions for the line number of the diagnostic.
128   * @throws AssertionError if the diagnostic is null.
129   */
130  public AbstractLongAssert<?> lineNumber() {
131    isNotNull();
132
133    return assertThat(actual.getLineNumber()).describedAs("line number");
134  }
135
136  /**
137   * Get assertions for the column number of the diagnostic.
138   *
139   * <p>The value may be -1 if no information is available.
140   *
141   * @return the assertions for the column number of the diagnostic.
142   * @throws AssertionError if the diagnostic is null.
143   */
144  public AbstractLongAssert<?> columnNumber() {
145    isNotNull();
146
147    return assertThat(actual.getColumnNumber()).describedAs("column number");
148  }
149
150  /**
151   * Get assertions for the code of the diagnostic.
152   *
153   * @return the assertions for the code of the diagnostic.
154   * @throws AssertionError if the diagnostic is null.
155   */
156  public AbstractStringAssert<?> code() {
157    isNotNull();
158
159    return assertThat(actual.getCode()).describedAs("code");
160  }
161
162  /**
163   * Get assertions for the message of the diagnostic, assuming the default locale.
164   *
165   * @return the assertions for the message of the diagnostic.
166   * @throws AssertionError if the diagnostic is null.
167   */
168  public AbstractStringAssert<?> message() {
169    isNotNull();
170
171    return assertThat(actual.getMessage(null));
172  }
173
174  /**
175   * Get assertions for the message of the diagnostic.
176   *
177   * @param locale the locale to use.
178   * @return the assertions for the message of the diagnostic.
179   * @throws AssertionError if the diagnostic is null.
180   */
181  public AbstractStringAssert<?> message(Locale locale) {
182    requireNonNull(locale, "locale must not be null");
183
184    isNotNull();
185
186    return assertThat(actual.getMessage(locale));
187  }
188
189  /**
190   * Get assertions for the timestamp of the diagnostic.
191   *
192   * @return the assertions for the timestamp of the diagnostic.
193   * @throws AssertionError if the diagnostic is null.
194   */
195  public AbstractInstantAssert<?> timestamp() {
196    isNotNull();
197
198    return assertThat(actual.getTimestamp());
199  }
200
201  /**
202   * Get assertions for the thread ID of the thread that reported the diagnostic to the compiler.
203   *
204   * @return the assertions for the thread ID.
205   * @throws AssertionError if the diagnostic is null.
206   */
207  public AbstractLongAssert<?> threadId() {
208    isNotNull();
209
210    return assertThat(actual.getThreadId());
211  }
212
213  /**
214   * Get assertions for the thread name of the thread that reported the diagnostic.
215   *
216   * <p>This may not be present in some situations, in which case the returned assertions will be
217   * performed on a null value instead.
218   *
219   * @return the assertions for the thread name.
220   * @throws AssertionError if the diagnostic is null.
221   */
222  public AbstractStringAssert<?> threadName() {
223    isNotNull();
224
225    return assertThat(actual.getThreadName());
226  }
227
228  /**
229   * Get assertions for the stack trace of the location the diagnostic was reported to.
230   *
231   * @return the assertions for the stack trace.
232   * @throws AssertionError if the diagnostic is null.
233   */
234  public StackTraceAssert stackTrace() {
235    isNotNull();
236
237    return new StackTraceAssert(actual.getStackTrace());
238  }
239}