This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch ISIS-2222
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 7248a4779b90fa69b099481abebde6ec603a1626
Author: danhaywood <[email protected]>
AuthorDate: Wed Sep 9 08:31:25 2020 +0100

     ISIS-2222: reworking command, lots of stuff here...
---
 .../examples/services/DomainChangeRecord.java      | 155 +++++++++++++++++++++
 .../DomainChangeRecord_openTargetObject.java       |  61 ++++++++
 .../services/command/spi/CommandService.java       |  65 ---------
 .../applib/annotation/CommandReification.java}     |  34 +++--
 .../applib/services/command/CommandService.java    |  92 ++++++++++++
 .../command/spi/CommandServiceListener.java}       |  27 ++--
 .../impl/CommandServiceListenerForJdo.java         |  50 ++++---
 .../impl/util/StringUtils_trimmed_Test.java        |  28 ++++
 .../CommandReplayAnalysisService_trimmed_Test.java |  30 ----
 9 files changed, 403 insertions(+), 139 deletions(-)

diff --git 
a/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord.java
 
b/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord.java
new file mode 100644
index 0000000..ea81d3f
--- /dev/null
+++ 
b/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.services;
+
+import java.sql.Timestamp;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.Optionality;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.PropertyLayout;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.message.MessageService;
+import org.apache.isis.applib.services.metamodel.BeanSort;
+import org.apache.isis.applib.services.metamodel.MetaModelService;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+
+/**
+ * An abstraction of some sort of recorded change to a domain object: 
commands, audit entries or published events.
+ */
+public interface DomainChangeRecord extends HasUniqueId, HasUsername {
+
+    enum ChangeType {
+        COMMAND,
+        AUDIT_ENTRY,
+        PUBLISHED_INTERACTION;
+        @Override
+        public String toString() {
+            return name().replace("_", " ");
+        }
+    }
+
+    /**
+     * Distinguishes commands from audit entries from published 
events/interactions (when these are shown mixed together in a (standalone) 
table).
+     */
+    @Property
+    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Identifiers", sequence = "1")
+    ChangeType getType();
+
+
+    /**
+     * The unique identifier (a GUID) of the transaction in which this change 
occurred.
+     */
+    @Property
+    @MemberOrder(name="Identifiers",sequence = "50")
+    UUID getUniqueId();
+
+
+    /**
+     * The user that caused the change.
+     */
+    @Property
+    @MemberOrder(name="Identifiers", sequence = "10")
+    String getUsername();
+
+
+    /**
+     * The time that the change occurred.
+     */
+    @Property
+    @MemberOrder(name="Identifiers", sequence = "20")
+    Timestamp getTimestamp();
+
+
+    /**
+     * The object type of the domain object being changed.
+     */
+    @Property
+    @PropertyLayout(named="Class")
+    @MemberOrder(name="Target", sequence = "10")
+    default String getTargetObjectType() {
+        return getTarget().getObjectType();
+    }
+
+
+
+    /**
+     * The {@link Bookmark} identifying the domain object that has changed.
+     */
+    @Property
+    @PropertyLayout(named="Object")
+    @MemberOrder(name="Target", sequence="30")
+    Bookmark getTarget();
+
+
+    /**
+     * The member interaction (ie action invocation or property edit) which 
caused the domain object to be changed.
+     *
+     * <p>
+     *     Populated for commands and for published events that represent 
action invocations or property edits.
+     * </p>
+     */
+    @Property(optionality = Optionality.OPTIONAL)
+    @PropertyLayout(named="Member", hidden = 
Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Target", sequence = "20")
+    String getTargetMember();
+
+
+    /**
+     * The value of the property prior to it being changed.
+     *
+     * <p>
+     * Populated only for audit entries.
+     * </p>
+     */
+    @Property(optionality = Optionality.OPTIONAL)
+    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Detail",sequence = "6")
+    String getPreValue();
+
+
+    /**
+     * The value of the property after it has changed.
+     *
+     * <p>
+     * Populated only for audit entries.
+     * </p>
+     */
+    @Property(optionality = Optionality.MANDATORY)
+    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Detail",sequence = "7")
+    String getPostValue();
+
+
+}
diff --git 
a/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord_openTargetObject.java
 
b/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord_openTargetObject.java
new file mode 100644
index 0000000..7033bb5
--- /dev/null
+++ 
b/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord_openTargetObject.java
@@ -0,0 +1,61 @@
+package org.apache.isis.applib.services;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.message.MessageService;
+import org.apache.isis.applib.services.metamodel.BeanSort;
+import org.apache.isis.applib.services.metamodel.MetaModelService;
+
+@Action(
+        semantics = SemanticsOf.SAFE
+        , associateWith = "target"
+        , associateWithSequence = "1"
+)
+@ActionLayout(named = "Open")
+public class DomainChangeRecord_openTargetObject {
+
+    private final DomainChangeRecord domainChangeRecord;
+    public DomainChangeRecord_openTargetObject(DomainChangeRecord 
domainChangeRecord) {
+        this.domainChangeRecord = domainChangeRecord;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE, associateWith = "target", 
associateWithSequence = "1")
+    @ActionLayout(named = "Open")
+    public Object openTargetObject() {
+        try {
+            return bookmarkService != null
+                    ? bookmarkService.lookup(domainChangeRecord.getTarget())
+                    : null;
+        } catch(RuntimeException ex) {
+            if(ex.getClass().getName().contains("ObjectNotFoundException")) {
+                messageService.warnUser("Object not found - has it since been 
deleted?");
+                return null;
+            }
+            throw ex;
+        }
+    }
+
+    public boolean hideOpenTargetObject() {
+        return domainChangeRecord.getTarget() == null;
+    }
+
+    public String disableOpenTargetObject() {
+        final Object targetObject = domainChangeRecord.getTarget();
+        if (targetObject == null) {
+            return null;
+        }
+        final BeanSort sortOfObject = 
metaModelService.sortOf(domainChangeRecord.getTarget(), 
MetaModelService.Mode.RELAXED);
+        return !(sortOfObject.isViewModel() || sortOfObject.isEntity())
+                ? "Can only open view models or entities"
+                : null;
+    }
+
+    @Inject BookmarkService bookmarkService;
+    @Inject MessageService messageService;
+    @Inject MetaModelService metaModelService;
+
+}
diff --git 
a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandService.java
 
b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandService.java
deleted file mode 100644
index eb3abce..0000000
--- 
a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandService.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.services.command.spi;
-
-import org.apache.isis.applib.services.command.Command;
-
-/**
- * Default factory service for {@link Command}s.
- */
-// tag::refguide[]
-public interface CommandService {
-
-    // end::refguide[]
-    /**
-     * Simply instantiates the appropriate instance of the {@link Command}.
-     *
-     * <p>
-     * Its members will be populated automatically by the framework (the 
{@link Command}'s
-     * {@link Command#getTimestamp()}, {@link Command#getUser()} and {@link 
Command#getUniqueId()}).
-     * </p>
-     */
-    // tag::refguide[]
-    Command create();                               // <.>
-    // end::refguide[]
-
-    /**
-     * Hint for this implementation to eagerly persist the {@link Command}s if 
possible; influences the behaviour
-     * of actions annotated to execute in the {@link 
org.apache.isis.applib.annotation.CommandExecuteIn#BACKGROUND}.
-     */
-    // tag::refguide[]
-    boolean persistIfPossible(Command command);     // <.>
-    // end::refguide[]
-
-    /**
-     * &quot;Complete&quot; the command, typically meaning to indicate that 
the command is completed, and to
-     * persist it if its {@link Command#getPersistence()} and {@link 
Command#isPersistHint() persistence hint}
-     * indicate that it should be.
-     *
-     * <p>
-     * However, not every implementation necessarily {@link 
#persistIfPossible(Command) supports persistence}.
-     *
-     * <p>
-     *     The framework will automatically have set the {@link 
Command#getCompletedAt()} property.
-     * </p>
-     */
-    // tag::refguide[]
-    void complete(final Command command);           // <.>
-}
-// end::refguide[]
diff --git 
a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandPersistence.java
 
b/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandReification.java
similarity index 50%
rename from 
api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandPersistence.java
rename to 
api/applib/src/main/java/org/apache/isis/applib/annotation/CommandReification.java
index 7f7000a..a2b8b68 100644
--- 
a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandPersistence.java
+++ 
b/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandReification.java
@@ -19,34 +19,38 @@
 package org.apache.isis.applib.annotation;
 
 /**
- * Whether the command should be persisted.
+ * The available policies as to whether action invocations are reified into 
commands.
  */
 // tag::refguide[]
-public enum CommandPersistence {
-
+public enum CommandReification {
     // end::refguide[]
     /**
-     * (If the configured {@link 
org.apache.isis.applib.services.command.spi.CommandService} supports it), 
indicates that the
-     * {@link org.apache.isis.applib.services.command.Command Command} object 
should be persisted.
+     * Whether the action should be handled as a command as per the default 
command configured in <tt>applicationp.properties</tt>.
+     *
+     * <p>
+     *     If no command policy is configured, then the action is <i>not</i> 
treated as a command.
+     * </p>
      */
     // tag::refguide[]
-    PERSISTED,
+    AS_CONFIGURED,
     // end::refguide[]
     /**
-     * (If the configured {@link 
org.apache.isis.applib.services.command.spi.CommandService} supports it), 
indicates that the
-     * {@link org.apache.isis.applib.services.command.Command Command} object 
should only be persisted if
-     * another service, such as the {@link 
org.apache.isis.applib.services.background.BackgroundCommandService}, hints 
that it should.
+     * Handle the action as a command, irrespective of any configuration 
settings.
      */
     // tag::refguide[]
-    IF_HINTED,
+    ENABLED,
     // end::refguide[]
     /**
-     * (Even if the configured {@link 
org.apache.isis.applib.services.command.spi.CommandService} supports it), 
indicates that the
-     * {@link org.apache.isis.applib.services.command.Command Command} object 
should <i>not</i> be persisted (even if
-     * another service, such as the {@link 
org.apache.isis.applib.services.background.BackgroundCommandService}, hints 
that it should).
+     * Do not handle the action as a command, irrespective of any 
configuration settings.
      */
     // tag::refguide[]
-    NOT_PERSISTED
-
+    DISABLED,
+    // end::refguide[]
+    /**
+     * Ignore the value provided by this annotation (meaning that the 
framework will keep searching, in meta
+     * annotations or superclasses/interfaces).
+     */
+    // tag::refguide[]
+    NOT_SPECIFIED
 }
 // end::refguide[]
diff --git 
a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandService.java
 
b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandService.java
new file mode 100644
index 0000000..ce19893
--- /dev/null
+++ 
b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandService.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.services.command;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.annotation.IsisInteractionScope;
+import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.spi.CommandServiceListener;
+
+import lombok.extern.log4j.Log4j2;
+
+@Service
+@Named("isisApplib.CommandService")
+@Order(OrderPrecedence.MIDPOINT)
+@Primary
+@Qualifier("Default")
+@Log4j2
+// tag::refguide[]
+public class CommandService {
+
+    // end::refguide[]
+    /**
+     * Simply instantiates the appropriate instance of the {@link Command}.
+     *
+     * <p>
+     * Its members will be populated automatically by the framework (the
+     * {@link Command}'s {@link Command#getTimestamp()},
+     * {@link Command#getUsername()} and {@link Command#getUniqueId()}).
+     * </p>
+     */
+    // tag::refguide[]
+    public Command create() {                   // <.>
+        return new Command();
+    }
+
+    // end::refguide[]
+
+    /**
+     * &quot;Complete&quot; the command, providing an opportunity ot persist
+     * a memento of the command if the
+     * {@link Command#isSystemStateChanged() system state has changed}.
+     *
+     * <p>
+     *     The framework will automatically have set the {@link 
Command#getCompletedAt()} property.
+     * </p>
+     */
+    // tag::refguide[]
+    public void complete(final Command command) {   // <.>
+        // ...
+    // end::refguide[]
+
+        if(command.getLogicalMemberIdentifier() == null) {
+            // eg if seed fixtures
+            return;
+        }
+
+        log.debug("complete: {}, systemStateChanged {}", 
command.getLogicalMemberIdentifier(), command.isSystemStateChanged());
+
+    // tag::refguide[]
+        commandServiceListeners.forEach(x -> x.onComplete(command));
+    }
+
+    @Inject List<CommandServiceListener> commandServiceListeners;
+
+}
+// end::refguide[]
diff --git 
a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandWithDto.java
 
b/api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandServiceListener.java
similarity index 63%
rename from 
api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandWithDto.java
rename to 
api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandServiceListener.java
index cd421ea..5d10793 100644
--- 
a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandWithDto.java
+++ 
b/api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandServiceListener.java
@@ -16,20 +16,25 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.applib.services.command;
+package org.apache.isis.applib.services.command.spi;
 
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.schema.cmd.v2.CommandDto;
+import org.apache.isis.applib.services.command.Command;
 
+/**
+ * SPI
+ */
 // tag::refguide[]
-public interface CommandWithDto extends Command {
-
-    String USERDATA_KEY_TARGET_CLASS = "targetClass";
-    String USERDATA_KEY_TARGET_ACTION = "targetAction";
-    String USERDATA_KEY_ARGUMENTS = "arguments";
-    String USERDATA_KEY_RETURN_VALUE = "returnValue";
-    String USERDATA_KEY_EXCEPTION = "exception";
+public interface CommandServiceListener {
 
-    CommandDto asDto();
+    /**
+     * Notifies that the command has completed.
+     *
+     * <p>
+     *     This is an opportunity for implementations to process the command,
+     *     for example to persist a representation of it.
+     * </p>
+     */
+    // tag::refguide[]
+    void onComplete(final Command command);           // <.>
 }
 // end::refguide[]
diff --git 
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java
 
b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/CommandServiceListenerForJdo.java
similarity index 51%
rename from 
core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java
rename to 
extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/CommandServiceListenerForJdo.java
index 527692f..f3a4d81 100644
--- 
a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java
+++ 
b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/CommandServiceListenerForJdo.java
@@ -16,39 +16,53 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.core.runtimeservices.command;
+package org.apache.isis.extensions.commandlog.impl;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.spi.CommandService;
+import org.apache.isis.applib.services.command.spi.CommandServiceListener;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
+
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
 
 @Service
-@Named("isisRuntimeServices.CommandServiceDefault")
-@Order(OrderPrecedence.LATE)
-@Primary
-@Qualifier("Default")
-public class CommandServiceDefault implements CommandService {
+@Named("isisExtensionsCommandLog.CommandCompletionHook")
+@Order(OrderPrecedence.MIDPOINT) // after JdoPersistenceLifecycleService
+@Qualifier("Jdo")
+@Log4j2
+@RequiredArgsConstructor
+public class CommandServiceListenerForJdo implements CommandServiceListener {
 
-    @Override
-    public Command create() {
-        return new CommandDefault();
-    }
+    @Inject final CommandJdoRepository commandJdoRepository;
 
     @Override
-    public void complete(final Command command) {
-        // nothing to do
-    }
+    public void onComplete(Command command) {
 
-    @Override
-    public boolean persistIfPossible(final Command command) {
-        return false;
+        if(!command.isSystemStateChanged()) {
+            return;
+        }
+
+        val commandJdo = new CommandJdo(command);
+        val parent = command.getParent();
+        val parentJdo =
+            parent != null
+                ? commandJdoRepository
+                    .findByUniqueId(parent.getUniqueId())
+                    .orElse(null)
+                : null;
+        commandJdo.setParent(parentJdo);
+
+        commandJdoRepository.persist(commandJdo);
     }
 
 }
diff --git 
a/extensions/core/command-log/impl/src/test/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils_trimmed_Test.java
 
b/extensions/core/command-log/impl/src/test/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils_trimmed_Test.java
new file mode 100644
index 0000000..b991b25
--- /dev/null
+++ 
b/extensions/core/command-log/impl/src/test/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils_trimmed_Test.java
@@ -0,0 +1,28 @@
+package org.apache.isis.extensions.commandlog.impl.util;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class StringUtils_trimmed_Test {
+
+    @Test
+    public void fits() {
+        Assertions.assertThat(StringUtils.trimmed("abcde", 
5)).isEqualTo("abcde");
+    }
+
+    @Test
+    public void needs_to_be_trimmed() {
+        Assertions.assertThat(StringUtils.trimmed("abcde", 
4)).isEqualTo("a...");
+    }
+
+    @Test
+    public void when_null() {
+        Assertions.assertThat(StringUtils.trimmed(null, 4)).isNull();
+    }
+
+    @Test
+    public void when_empty() {
+        Assertions.assertThat(StringUtils.trimmed("", 4)).isEqualTo("");
+    }
+
+}
\ No newline at end of file
diff --git 
a/extensions/core/command-replay/impl/src/test/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService_trimmed_Test.java
 
b/extensions/core/command-replay/impl/src/test/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService_trimmed_Test.java
deleted file mode 100644
index babe14e..0000000
--- 
a/extensions/core/command-replay/impl/src/test/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService_trimmed_Test.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.isis.extensions.commandreplay.impl.analysis;
-
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-import 
org.apache.isis.extensions.commandreplay.impl.analysis.CommandReplayAnalysisService;
-
-public class CommandReplayAnalysisService_trimmed_Test {
-
-    @Test
-    public void fits() {
-        Assertions.assertThat(CommandReplayAnalysisService.trimmed("abcde", 
5)).isEqualTo("abcde");
-    }
-
-    @Test
-    public void needs_to_be_trimmed() {
-        Assertions.assertThat(CommandReplayAnalysisService.trimmed("abcde", 
4)).isEqualTo("a...");
-    }
-
-    @Test
-    public void when_null() {
-        Assertions.assertThat(CommandReplayAnalysisService.trimmed(null, 
4)).isNull();
-    }
-
-    @Test
-    public void when_empty() {
-        Assertions.assertThat(CommandReplayAnalysisService.trimmed("", 
4)).isEqualTo("");
-    }
-
-}
\ No newline at end of file

Reply via email to