Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/org/labkey/test/BaseWebDriverTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import org.junit.runners.model.MultipleFailureException;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestTimedOutException;
import org.labkey.api.query.FieldKey;
import org.labkey.junit.rules.TestWatcher;
import org.labkey.remoteapi.CommandException;
import org.labkey.remoteapi.CommandResponse;
Expand All @@ -65,6 +64,7 @@
import org.labkey.test.pages.query.NewQueryPage;
import org.labkey.test.pages.query.SourceQueryPage;
import org.labkey.test.pages.search.SearchResultsPage;
import org.labkey.test.params.FieldKey;
import org.labkey.test.teamcity.TeamCityUtils;
import org.labkey.test.util.APIAssayHelper;
import org.labkey.test.util.APIContainerHelper;
Expand Down Expand Up @@ -215,8 +215,9 @@ public abstract class BaseWebDriverTest extends LabKeySiteWrapper implements Cle

public static final double DELTA = 10E-10;

public static final String[] ILLEGAL_QUERY_KEY_CHARACTERS = FieldKey.ILLEGAL;
public static final String ALL_ILLEGAL_QUERY_KEY_CHARACTERS = StringUtils.join(ILLEGAL_QUERY_KEY_CHARACTERS, "");
@Deprecated // Going away soon
public static final String[] ILLEGAL_QUERY_KEY_CHARACTERS = FieldKey.getIllegalChars().toArray(new String[0]);
public static final String ALL_ILLEGAL_QUERY_KEY_CHARACTERS = StringUtils.join(FieldKey.getIllegalChars(), "");
// See TSVWriter.shouldQuote. Generally we are not able to use the tab and new line characters when creating field names in the UI, but including here for completeness
public static final String[] TRICKY_IMPORT_FIELD_CHARACTERS = {"\\", "\"", "\\t", ",", "\\n", "\\r"};

Expand Down
17 changes: 16 additions & 1 deletion src/org/labkey/test/components/ui/grids/EditableGrid.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public List<String> getColumnLabels()
return elementCache().getColumnLabels();
}

protected Integer getColumnIndex(CharSequence columnIdentifier)
public Integer getColumnIndex(CharSequence columnIdentifier)
{
return elementCache().getColumnIndex(columnIdentifier);
}
Expand Down Expand Up @@ -258,6 +258,21 @@ public List<Map<String, String>> getGridDataByName(CharSequence... columnIdentif
return getGridData(FieldReference::getName, columnIdentifiers);
}

/**
* @param columnIdentifiers fieldKeys, names, or labels of columns
* @return grid data for the specified columns, ordered as the provided columnIdentifiers
*/
public List<List<String>> getGridData(CharSequence... columnIdentifiers)
{
List<Map<Integer, String>> rowMaps = getGridData(FieldReference::getDomIndex, columnIdentifiers);
List<List<String>> gridData = new ArrayList<>();
for (Map<Integer, String> gridMap : rowMaps)
{
gridData.add(new ArrayList<>(gridMap.values())); // row maps remember insertion order
}
return gridData;
}

private <T> List<Map<T, String>> getGridData(Function<FieldReferenceManager.FieldReference, T> keyGenerator, CharSequence... columnIdentifiers)
{
List<Map<T, String>> gridData = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
import org.labkey.test.params.FieldKey;
import org.labkey.test.params.WrapsFieldKey;
import org.labkey.test.util.selenium.WebElementUtils;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;
Expand Down Expand Up @@ -43,9 +44,9 @@ public final FieldReference findFieldReference(CharSequence fieldIdentifier)
{
List<Supplier<FieldReference>> options;

if (fieldIdentifier instanceof FieldKey fk)
if (fieldIdentifier instanceof WrapsFieldKey fk)
{
options = List.of(() -> findColumnHeaderByFieldKey(fk)); // We know it is a FieldKey
options = List.of(() -> findColumnHeaderByFieldKey(fk.getFieldKey())); // We know it is a FieldKey
}
else
{
Expand Down
104 changes: 94 additions & 10 deletions src/org/labkey/test/params/FieldInfo.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
package org.labkey.test.params;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.labkey.test.params.FieldDefinition.ColumnType;
import org.labkey.test.util.EscapeUtil;
import org.labkey.test.util.TestDataGenerator;

import java.util.Objects;
import java.util.function.Consumer;

/**
* Immutable alternative to 'FieldDefinition'
* Use this for shared global field information
* Implements CharSequence to be compatible with grid components
*/
public class FieldInfo
public class FieldInfo implements CharSequence, WrapsFieldKey
{
private final FieldKey _fieldKey;
private final String _label;
private final FieldDefinition.ColumnType _columnType;
private final ColumnType _columnType;
private final Consumer<FieldDefinition> _fieldDefinitionMutator;

private FieldInfo(FieldKey fieldKey, String label, FieldDefinition.ColumnType columnType, Consumer<FieldDefinition> fieldDefinitionMutator)
private FieldInfo(FieldKey fieldKey, String label, ColumnType columnType, Consumer<FieldDefinition> fieldDefinitionMutator)
{
_fieldKey = fieldKey;
_label = label;
_columnType = Objects.requireNonNullElse(columnType, FieldDefinition.ColumnType.String);
_columnType = Objects.requireNonNullElse(columnType, ColumnType.String);
_fieldDefinitionMutator = fieldDefinitionMutator;
}

public FieldInfo(String name, String label, FieldDefinition.ColumnType columnType)
public FieldInfo(String name, String label, ColumnType columnType)
{
this(FieldKey.fromParts(name.trim()), label, columnType, null);
}
Expand All @@ -32,7 +39,7 @@ public FieldInfo(String name, String label)
this(name, label, null);
}

public FieldInfo(String name, FieldDefinition.ColumnType columnType)
public FieldInfo(String name, ColumnType columnType)
{
this(name, null, columnType);
}
Expand All @@ -42,61 +49,114 @@ public FieldInfo(String name)
this(name, null, null);
}

/**
* Creates a FieldInfo with a semi-random name
*/
public static FieldInfo random(String namePart, ColumnType columnType)
{
return new FieldInfo(TestDataGenerator.randomFieldName(namePart), columnType);
}

/**
* Creates a String field with a semi-random name
*/
public static FieldInfo random(String namePart)
{
return random(namePart, null);
}

/**
*
* @param fieldDefinitionMutator will be invoked by {@link #getFieldDefinition()}
* @return a new FieldInfo with the provided mutator. Any existing mutator will be replaced.
*/
@Contract(pure = true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious to know the use case for a Consumer of FieldDefinition

public FieldInfo customizeFieldDefinition(Consumer<FieldDefinition> fieldDefinitionMutator)
{
FieldDefinition verifier = new FieldDefinition("temp", _columnType);
fieldDefinitionMutator.accept(verifier);
if (verifier.getLabel() != null)
{
throw new IllegalArgumentException("FieldDefinition customizer should not modify field label");
}
return new FieldInfo(_fieldKey, _label, _columnType, fieldDefinitionMutator);
}

@Contract(pure = true)
protected String getRawLabel()
{
return _label;
}

@Contract(pure = true)
public String getLabel()
{
return Objects.requireNonNullElseGet(getRawLabel(), () -> FieldDefinition.labelFromName(_fieldKey.getName()));
}

@Override
@Contract(pure = true)
public FieldKey getFieldKey()
{
return _fieldKey;
}

@Contract(pure = true)
public String getName()
{
return _fieldKey.getName();
}

/**
* Get name escaped for use in sample or source name expressions
*/
@Contract(pure = true)
public String getExpName()
{
return EscapeUtil.escapeForNameExpression(getName());
}

@Contract(pure = true)
public FieldKey child(String name)
{
return _fieldKey.child(name);
}

/**
* @return A FieldDefinition to be used for domain creation
*/
@Contract(pure = true)
public FieldDefinition getFieldDefinition()
{
return getFieldDefinition(_columnType);
}

/**
* Shared lookup definitions might want to customize the target table.
* @param lookupContainerPath the containerPath to use for the lookup
* @return A FieldDefinition to be used for domain creation
*/
@Contract(pure = true)
public FieldDefinition getFieldDefinition(String lookupContainerPath)
{
if (!_columnType.isLookup())
{
throw new IllegalArgumentException("Unable to set lookup container for %s column: %s".formatted(_columnType.getLabel(), getName()));
throw new IllegalArgumentException("Unable to set lookup container for %s column: %s".formatted(_columnType.getLabel(), _fieldKey.getName()));
}
else
{
String schema = _columnType.getLookupInfo().getSchema();
String table = _columnType.getLookupInfo().getTable();
FieldDefinition.ColumnType columnType = _columnType.getRangeURI().equals(FieldDefinition.ColumnType.Integer.getRangeURI())
ColumnType columnType = _columnType.getRangeURI().equals(ColumnType.Integer.getRangeURI())
? new FieldDefinition.IntLookup(lookupContainerPath, schema, table)
: new FieldDefinition.StringLookup(lookupContainerPath, schema, table);
return getFieldDefinition(columnType);
}
}

private FieldDefinition getFieldDefinition(FieldDefinition.ColumnType columnType)
private FieldDefinition getFieldDefinition(ColumnType columnType)
{
FieldDefinition fieldDefinition = new FieldDefinition(getName(), columnType);
FieldDefinition fieldDefinition = new FieldDefinition(_fieldKey.getName(), columnType);
if (getRawLabel() != null)
{
fieldDefinition.setLabel(getRawLabel());
Expand All @@ -107,4 +167,28 @@ private FieldDefinition getFieldDefinition(FieldDefinition.ColumnType columnType
}
return fieldDefinition;
}

@Override
public int length()
{
return _fieldKey.length();
}

@Override
public char charAt(int index)
{
return _fieldKey.charAt(index);
}

@Override
public @NotNull CharSequence subSequence(int start, int end)
{
return _fieldKey.subSequence(start, end);
}

@Override
public @NotNull String toString()
{
return _fieldKey.toString();
}
}
40 changes: 26 additions & 14 deletions src/org/labkey/test/params/FieldKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
import java.util.Iterator;
import java.util.List;

public class FieldKey implements CharSequence
public final class FieldKey implements CharSequence, WrapsFieldKey
{
private static final String[] ILLEGAL = {"$", "/", "&", "}", "~", ",", "."};
private static final String[] REPLACEMENT = {"$D", "$S", "$A", "$B", "$T", "$C", "$P"};

public static final FieldKey EMPTY = new FieldKey(""); // Useful as a sort of FieldKey builder starting point
public static final FieldKey SOURCES_FK = new FieldKey("DataInputs");
public static final FieldKey PARENTS_FK = new FieldKey("MaterialInputs");
Expand All @@ -36,14 +39,17 @@ private FieldKey(FieldKey parent, String child)
_fieldKey = parent + SEPARATOR + encodePart(child);
}

public static List<String> getIllegalChars()
{
return List.of(ILLEGAL);
}

public static FieldKey fromParts(List<String> parts)
{
FieldKey fieldKey = EMPTY;

for (String part : parts)
{
if (StringUtils.isBlank(part))
throw new IllegalArgumentException("FieldKey contains a blank part: " + parts);
fieldKey = fieldKey.child(part);
}

Expand All @@ -62,9 +68,9 @@ public static FieldKey fromParts(String... parts)
*/
public static @Nullable FieldKey fromFieldKey(CharSequence fieldKey)
{
if (fieldKey instanceof FieldKey fk)
if (fieldKey instanceof WrapsFieldKey fk)
{
return fk;
return fk.getFieldKey();
}
else
{
Expand All @@ -86,15 +92,12 @@ public static FieldKey fromParts(String... parts)
*/
public static FieldKey fromName(CharSequence nameOrFieldKey)
{
if (nameOrFieldKey instanceof FieldKey fk)
return fk;
if (nameOrFieldKey instanceof WrapsFieldKey fk)
return fk.getFieldKey();
else
return fromParts(nameOrFieldKey.toString());
}

private static final String[] ILLEGAL = {"$", "/", "&", "}", "~", ",", "."};
private static final String[] REPLACEMENT = {"$D", "$S", "$A", "$B", "$T", "$C", "$P"};

public static String encodePart(String str)
{
return StringUtils.replaceEach(str, ILLEGAL, REPLACEMENT);
Expand All @@ -110,15 +113,18 @@ public FieldKey getParent()
return _parent;
}

public FieldKey child(String name)
public FieldKey child(String part)
{
if (StringUtils.isBlank(part))
throw new IllegalArgumentException("FieldKey can't have blank part(s): " + this);

if (StringUtils.isBlank(getName()))
{
return new FieldKey(name);
return new FieldKey(part);
}
else
{
return new FieldKey(this, name);
return new FieldKey(this, part);
}
}

Expand Down Expand Up @@ -148,6 +154,12 @@ public String[] getNameArray()
return Arrays.stream(_fieldKey.split(SEPARATOR)).map(FieldKey::decodePart).toArray(String[]::new);
}

@Override
public FieldKey getFieldKey()
{
return this;
}

@Override
public @NotNull String toString()
{
Expand All @@ -173,7 +185,7 @@ public char charAt(int index)
}

@Override
public final boolean equals(Object o)
public boolean equals(Object o)
{
if (!(o instanceof FieldKey fieldKey)) return false;

Expand Down
6 changes: 6 additions & 0 deletions src/org/labkey/test/params/WrapsFieldKey.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.labkey.test.params;

public interface WrapsFieldKey
{
FieldKey getFieldKey();
}
Loading