Class ExpressionExperimentReadServiceAnnotationsTest

java.lang.Object
ubic.gemma.persistence.service.expression.experiment.ExpressionExperimentReadServiceAnnotationsTest

@ExtendWith(org.mockito.junit.jupiter.MockitoExtension.class) public class ExpressionExperimentReadServiceAnnotationsTest extends Object
De-duplication contract of ExpressionExperimentReadServiceImpl.getAnnotations(ExpressionExperiment, boolean).

The three sources it aggregates (experiment tags, factor-value statements, sample characteristics) overlap, so the aggregate is de-duplicated. The key is the category, the term's value and the statement shape hanging off it; the shapes below pin what that must and must not collapse. Both collapse cases were measured on production first, so neither is hypothetical.

Also pins what value holds: the term, on every row. Nothing here composes a sentence.

  • Constructor Details

    • ExpressionExperimentReadServiceAnnotationsTest

      public ExpressionExperimentReadServiceAnnotationsTest()
  • Method Details

    • setUp

      @BeforeEach public void setUp()
    • getAnnotations_sameTermUnderTwoCategories_returnsBoth

      @Test public void getAnnotations_sameTermUnderTwoCategories_returnsBoth()
      Two experiment tags on the same term under different categories are two distinct curation claims, and both must be returned. Measured on production: experiment 5402 stores cell type and organism part rows that both point at CL_1001610, and the route returned only the first.
    • getAnnotations_sameTermUnderSameCategory_collapses

      @Test public void getAnnotations_sameTermUnderSameCategory_collapses()
      Exact duplicates — same category and same term — still collapse. That is what the aggregation of three overlapping sources is for, and it is the behaviour the category-aware key must not lose.
    • getAnnotations_sameTermAndCategoryDifferingStatement_returnsBoth

      @Test public void getAnnotations_sameTermAndCategoryDifferingStatement_returnsBoth()
      Regression guard for the negative control measured on experiment 27103: two factor-value statements that share a term URI and a category, differing only in their predicate/object, both come back. Both now report the same value — the term — so the predicate/object labels are the only thing keeping them apart, in the de-duplication key and in the VO's own equality. The statements carry no ids here on purpose: that is the state both gates have to hold up in, and it is the state a transient VO is in.
    • getAnnotations_sameTagAtExperimentAndSampleLevel_collapses

      @Test public void getAnnotations_sameTagAtExperimentAndSampleLevel_collapses()
      The same tag reaching the aggregate from two different levels still collapses to one entry — objectClass is not part of the de-duplication key.
    • getAnnotations_statementRow_valueIsTheTermNotASentence

      @Test public void getAnnotations_statementRow_valueIsTheTermNotASentence()
      🛑 On a factor-value statement row value is the subject's label and nothing else. The predicate and object are returned in their own fields; a caller that wants "wild type genotype has background APP/PS1" builds it, and this route does not.
    • getAnnotations_reversedPredicateStatement_valueIsStillTheTerm

      @Test public void getAnnotations_reversedPredicateStatement_valueIsStillTheTerm()
      The second composition shape, and the one that hid the term worst: a reversed predicate (RO_0002200 has phenotype) put the object in front of the subject and dropped the predicate altogether, so "headache" was reported as "acute headache". The value is the subject either way.
    • getAnnotations_plainTag_valueIsTheTermAndStatementFieldsAreNull

      @Test public void getAnnotations_plainTag_valueIsTheTermAndStatementFieldsAreNull()
      A plain tag has no statement, so the predicate/object fields stay null and the value is the term.
    • getAnnotations_defaultsToIncludingUngroundedTags

      @Test public void getAnnotations_defaultsToIncludingUngroundedTags()
      🛑 Paul, 2026-08-31: "annotations should ALWAYS show ALL the annotations, including ungrounded EEtags." The old default hid tags with no ontology mapping, and a caller cannot tell an incomplete list from a complete one by inspecting it — it cost a curator an hour hunting a strain tag that was there all along, and silently truncated a corpus snapshot taken through this route.