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