diff --git a/.github/workflows/patrol-prepare.yaml b/.github/workflows/patrol-prepare.yaml index 2141ee5cc..1654c0908 100644 --- a/.github/workflows/patrol-prepare.yaml +++ b/.github/workflows/patrol-prepare.yaml @@ -155,13 +155,14 @@ jobs: - name: Run unit tests working-directory: packages/patrol/example/ios run: | + set -o pipefail xcodebuild test \ -workspace Runner.xcworkspace \ -scheme Runner \ -only-testing RunnerTests \ -configuration Debug \ -sdk iphoneos -destination 'platform=iOS Simulator,name=iPhone 14' \ - -derivedDataPath ../build/ios_unit | xcbeautify + -derivedDataPath ../build/ios_unit | xcbeautify --renderer github-actions prepare-flutter: name: Flutter ${{ matrix.flutter-version }} diff --git a/contracts.proto b/contracts.proto index 58842f1ec..27d2e105c 100644 --- a/contracts.proto +++ b/contracts.proto @@ -9,17 +9,18 @@ service PatrolAppService { } message ListDartTestsResponse { - DartTestGroup group = 1; + DartGroupEntry group = 1; } -message DartTestGroup { +message DartGroupEntry { string name = 1; - repeated DartTestCase tests = 2; - repeated DartTestGroup groups = 3; -} + GroupEntryType type = 3; + repeated DartGroupEntry entries = 4; -message DartTestCase { - string name = 1; + enum GroupEntryType { + GROUP = 0; + TEST = 1; + } } message RunDartTestRequest { diff --git a/dev/cli_tests/patrol_develop_test.dart b/dev/cli_tests/patrol_develop_test.dart index 5f7cdcfb9..45feec394 100644 --- a/dev/cli_tests/patrol_develop_test.dart +++ b/dev/cli_tests/patrol_develop_test.dart @@ -58,7 +58,7 @@ void main(List args) async { [ 'develop', ...['--target', 'integration_test/example_test.dart'], - ...args + ...args, ], runInShell: true, workingDirectory: exampleAppDirectory.path, diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/ContractsExtensions.kt b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/ContractsExtensions.kt index 30d74952e..69100a636 100644 --- a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/ContractsExtensions.kt +++ b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/ContractsExtensions.kt @@ -3,10 +3,11 @@ package pl.leancode.patrol import androidx.test.uiautomator.By import androidx.test.uiautomator.BySelector import androidx.test.uiautomator.UiSelector -import pl.leancode.patrol.contracts.Contracts -import pl.leancode.patrol.contracts.Contracts.DartTestGroup +import pl.leancode.patrol.contracts.Contracts.DartGroupEntry +import pl.leancode.patrol.contracts.Contracts.Selector +import pl.leancode.patrol.contracts.copy -private fun Contracts.Selector.isEmpty(): Boolean { +private fun Selector.isEmpty(): Boolean { return ( !hasText() && !hasTextStartsWith() && @@ -23,7 +24,7 @@ private fun Contracts.Selector.isEmpty(): Boolean { ) } -fun Contracts.Selector.toUiSelector(): UiSelector { +fun Selector.toUiSelector(): UiSelector { var selector = UiSelector() if (hasText()) { @@ -77,7 +78,7 @@ fun Contracts.Selector.toUiSelector(): UiSelector { return selector } -fun Contracts.Selector.toBySelector(): BySelector { +fun Selector.toBySelector(): BySelector { if (isEmpty()) { throw PatrolException("Selector is empty") } @@ -184,21 +185,28 @@ fun Contracts.Selector.toBySelector(): BySelector { return bySelector } -fun DartTestGroup.listFlatDartFiles(): List { - val files = mutableListOf() - for (group in groupsList) { - files.addAll(group.listGroups()) - } - - return files -} - -// Recursively lists groups in this group. -private fun DartTestGroup.listGroups(): List { - val groups = mutableListOf(this.name) - for (group in groupsList) { - groups.addAll(group.listGroups()) - } - - return groups +/** + * Flattens the structure of a DartTestSuite into a flat list of tests. + */ +fun DartGroupEntry.listTestsFlat(parentGroupName: String = ""): List { + val tests = mutableListOf() + + for (test in entriesList) { + if (test.type == DartGroupEntry.GroupEntryType.TEST) { + if (parentGroupName.isEmpty()) { + // This case is invalid, because every test will have at least 1 named group - its filename. + throw IllegalStateException("Invariant violated: test $test has no named parent group") + } + + tests.add(test.copy { name = "$parentGroupName ${test.name}" }) + } else if (test.type == DartGroupEntry.GroupEntryType.GROUP) { + if (parentGroupName.isEmpty()) { + tests.addAll(test.listTestsFlat(parentGroupName = test.name)) + } else { + tests.addAll(test.listTestsFlat(parentGroupName = "$parentGroupName ${test.name}")) + } + } + } + + return tests } diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolAppServiceClient.java b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolAppServiceClient.java index 68caee0b4..880d1e2ee 100644 --- a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolAppServiceClient.java +++ b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolAppServiceClient.java @@ -28,7 +28,7 @@ public PatrolAppServiceClient(String target) { blockingStub = PatrolAppServiceGrpc.newBlockingStub(channel); } - public DartTestGroup listDartTests() throws StatusRuntimeException { + public DartGroupEntry listDartTests() throws StatusRuntimeException { Empty request = Empty.newBuilder().build(); ListDartTestsResponse response = blockingStub.listDartTests(request); diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolJUnitRunner.java b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolJUnitRunner.java index fffe13014..e5802e57b 100644 --- a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolJUnitRunner.java +++ b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/PatrolJUnitRunner.java @@ -11,11 +11,13 @@ import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnitRunner; import io.grpc.StatusRuntimeException; -import pl.leancode.patrol.contracts.Contracts.DartTestGroup; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.concurrent.ExecutionException; +import static pl.leancode.patrol.contracts.Contracts.DartGroupEntry; import static pl.leancode.patrol.contracts.Contracts.RunDartTestResponse; /** @@ -53,7 +55,8 @@ public void onCreate(Bundle arguments) { * This default behavior doesn't work with Flutter apps. That's because in Flutter * apps, the tests are in the app itself, so running only the instrumentation * during the initial run is not enough. - * The app must also be run, and queried for Dart tests That's what this method does. + * The app must also be run, and queried for Dart tests. + * That's what this method does. *

*/ public void setUp(Class activityClass) { @@ -106,10 +109,15 @@ public Object[] listDartTests() { final String TAG = "PatrolJUnitRunner.listDartTests(): "; try { - final DartTestGroup dartTestGroup = patrolAppServiceClient.listDartTests(); - Object[] dartTestFiles = ContractsExtensionsKt.listFlatDartFiles(dartTestGroup).toArray(); - Logger.INSTANCE.i(TAG + "Got Dart tests: " + Arrays.toString(dartTestFiles)); - return dartTestFiles; + final DartGroupEntry dartTestGroup = patrolAppServiceClient.listDartTests(); + List dartTestCases = ContractsExtensionsKt.listTestsFlat(dartTestGroup, ""); + List dartTestCaseNamesList = new ArrayList<>(); + for (DartGroupEntry dartTestCase : dartTestCases) { + dartTestCaseNamesList.add(dartTestCase.getName()); + } + Object[] dartTestCaseNames = dartTestCaseNamesList.toArray(); + Logger.INSTANCE.i(TAG + "Got Dart tests: " + Arrays.toString(dartTestCaseNames)); + return dartTestCaseNames; } catch (StatusRuntimeException e) { Logger.INSTANCE.e(TAG + "Failed to list Dart tests: ", e); throw e; diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/Contracts.java b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/Contracts.java index 22199865b..a05cc7707 100644 --- a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/Contracts.java +++ b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/Contracts.java @@ -13,15 +13,15 @@ public interface ListDartTestsResponseOrBuilder extends com.google.protobuf.MessageLiteOrBuilder { /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; * @return Whether the group field is set. */ boolean hasGroup(); /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; * @return The group. */ - pl.leancode.patrol.contracts.Contracts.DartTestGroup getGroup(); + pl.leancode.patrol.contracts.Contracts.DartGroupEntry getGroup(); } /** * Protobuf type {@code patrol.ListDartTestsResponse} @@ -33,50 +33,51 @@ public static final class ListDartTestsResponse extends ListDartTestsResponseOrBuilder { private ListDartTestsResponse() { } + private int bitField0_; public static final int GROUP_FIELD_NUMBER = 1; - private pl.leancode.patrol.contracts.Contracts.DartTestGroup group_; + private pl.leancode.patrol.contracts.Contracts.DartGroupEntry group_; /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ @java.lang.Override public boolean hasGroup() { - return group_ != null; + return ((bitField0_ & 0x00000001) != 0); } /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ @java.lang.Override - public pl.leancode.patrol.contracts.Contracts.DartTestGroup getGroup() { - return group_ == null ? pl.leancode.patrol.contracts.Contracts.DartTestGroup.getDefaultInstance() : group_; + public pl.leancode.patrol.contracts.Contracts.DartGroupEntry getGroup() { + return group_ == null ? pl.leancode.patrol.contracts.Contracts.DartGroupEntry.getDefaultInstance() : group_; } /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ - private void setGroup(pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + private void setGroup(pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { value.getClass(); group_ = value; - + bitField0_ |= 0x00000001; } /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ @java.lang.SuppressWarnings({"ReferenceEquality"}) - private void mergeGroup(pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + private void mergeGroup(pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { value.getClass(); if (group_ != null && - group_ != pl.leancode.patrol.contracts.Contracts.DartTestGroup.getDefaultInstance()) { + group_ != pl.leancode.patrol.contracts.Contracts.DartGroupEntry.getDefaultInstance()) { group_ = - pl.leancode.patrol.contracts.Contracts.DartTestGroup.newBuilder(group_).mergeFrom(value).buildPartial(); + pl.leancode.patrol.contracts.Contracts.DartGroupEntry.newBuilder(group_).mergeFrom(value).buildPartial(); } else { group_ = value; } - + bitField0_ |= 0x00000001; } /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ private void clearGroup() { group_ = null; - + bitField0_ = (bitField0_ & ~0x00000001); } public static pl.leancode.patrol.contracts.Contracts.ListDartTestsResponse parseFrom( @@ -159,7 +160,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.ListDartTestsResponse prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -177,46 +178,46 @@ private Builder() { /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ @java.lang.Override public boolean hasGroup() { return instance.hasGroup(); } /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ @java.lang.Override - public pl.leancode.patrol.contracts.Contracts.DartTestGroup getGroup() { + public pl.leancode.patrol.contracts.Contracts.DartGroupEntry getGroup() { return instance.getGroup(); } /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ - public Builder setGroup(pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + public Builder setGroup(pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { copyOnWrite(); instance.setGroup(value); return this; } /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ public Builder setGroup( - pl.leancode.patrol.contracts.Contracts.DartTestGroup.Builder builderForValue) { + pl.leancode.patrol.contracts.Contracts.DartGroupEntry.Builder builderForValue) { copyOnWrite(); instance.setGroup(builderForValue.build()); return this; } /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ - public Builder mergeGroup(pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + public Builder mergeGroup(pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { copyOnWrite(); instance.mergeGroup(value); return this; } /** - * .patrol.DartTestGroup group = 1; + * .patrol.DartGroupEntry group = 1; */ public Builder clearGroup() { copyOnWrite(); instance.clearGroup(); @@ -239,10 +240,11 @@ protected final java.lang.Object dynamicMethod( } case BUILD_MESSAGE_INFO: { java.lang.Object[] objects = new java.lang.Object[] { + "bitField0_", "group_", }; java.lang.String info = - "\u0000\u0001\u0000\u0000\u0001\u0001\u0001\u0000\u0000\u0000\u0001\t"; + "\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0000\u0000\u0000\u0001\u1009\u0000"; return newMessageInfo(DEFAULT_INSTANCE, info, objects); } // fall through @@ -297,8 +299,8 @@ public static com.google.protobuf.Parser parser() { } } - public interface DartTestGroupOrBuilder extends - // @@protoc_insertion_point(interface_extends:patrol.DartTestGroup) + public interface DartGroupEntryOrBuilder extends + // @@protoc_insertion_point(interface_extends:patrol.DartGroupEntry) com.google.protobuf.MessageLiteOrBuilder { /** @@ -314,46 +316,131 @@ public interface DartTestGroupOrBuilder extends getNameBytes(); /** - * repeated .patrol.DartTestCase tests = 2; - */ - java.util.List - getTestsList(); - /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @return The enum numeric value on the wire for type. */ - pl.leancode.patrol.contracts.Contracts.DartTestCase getTests(int index); + int getTypeValue(); /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @return The type. */ - int getTestsCount(); + pl.leancode.patrol.contracts.Contracts.DartGroupEntry.GroupEntryType getType(); /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - java.util.List - getGroupsList(); + java.util.List + getEntriesList(); /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - pl.leancode.patrol.contracts.Contracts.DartTestGroup getGroups(int index); + pl.leancode.patrol.contracts.Contracts.DartGroupEntry getEntries(int index); /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - int getGroupsCount(); + int getEntriesCount(); } /** - * Protobuf type {@code patrol.DartTestGroup} + * Protobuf type {@code patrol.DartGroupEntry} */ - public static final class DartTestGroup extends + public static final class DartGroupEntry extends com.google.protobuf.GeneratedMessageLite< - DartTestGroup, DartTestGroup.Builder> implements - // @@protoc_insertion_point(message_implements:patrol.DartTestGroup) - DartTestGroupOrBuilder { - private DartTestGroup() { + DartGroupEntry, DartGroupEntry.Builder> implements + // @@protoc_insertion_point(message_implements:patrol.DartGroupEntry) + DartGroupEntryOrBuilder { + private DartGroupEntry() { name_ = ""; - tests_ = emptyProtobufList(); - groups_ = emptyProtobufList(); + entries_ = emptyProtobufList(); } + /** + * Protobuf enum {@code patrol.DartGroupEntry.GroupEntryType} + */ + public enum GroupEntryType + implements com.google.protobuf.Internal.EnumLite { + /** + * GROUP = 0; + */ + GROUP(0), + /** + * TEST = 1; + */ + TEST(1), + UNRECOGNIZED(-1), + ; + + /** + * GROUP = 0; + */ + public static final int GROUP_VALUE = 0; + /** + * TEST = 1; + */ + public static final int TEST_VALUE = 1; + + + @java.lang.Override + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static GroupEntryType valueOf(int value) { + return forNumber(value); + } + + public static GroupEntryType forNumber(int value) { + switch (value) { + case 0: return GROUP; + case 1: return TEST; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static final com.google.protobuf.Internal.EnumLiteMap< + GroupEntryType> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + @java.lang.Override + public GroupEntryType findValueByNumber(int number) { + return GroupEntryType.forNumber(number); + } + }; + + public static com.google.protobuf.Internal.EnumVerifier + internalGetVerifier() { + return GroupEntryTypeVerifier.INSTANCE; + } + + private static final class GroupEntryTypeVerifier implements + com.google.protobuf.Internal.EnumVerifier { + static final com.google.protobuf.Internal.EnumVerifier INSTANCE = new GroupEntryTypeVerifier(); + @java.lang.Override + public boolean isInRange(int number) { + return GroupEntryType.forNumber(number) != null; + } + }; + + private final int value; + + private GroupEntryType(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:patrol.DartGroupEntry.GroupEntryType) + } + public static final int NAME_FIELD_NUMBER = 1; private java.lang.String name_; /** @@ -401,238 +488,186 @@ private void setNameBytes( } - public static final int TESTS_FIELD_NUMBER = 2; - private com.google.protobuf.Internal.ProtobufList tests_; + public static final int TYPE_FIELD_NUMBER = 3; + private int type_; /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @return The enum numeric value on the wire for type. */ @java.lang.Override - public java.util.List getTestsList() { - return tests_; + public int getTypeValue() { + return type_; } /** - * repeated .patrol.DartTestCase tests = 2; - */ - public java.util.List - getTestsOrBuilderList() { - return tests_; - } - /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @return The type. */ @java.lang.Override - public int getTestsCount() { - return tests_.size(); + public pl.leancode.patrol.contracts.Contracts.DartGroupEntry.GroupEntryType getType() { + pl.leancode.patrol.contracts.Contracts.DartGroupEntry.GroupEntryType result = pl.leancode.patrol.contracts.Contracts.DartGroupEntry.GroupEntryType.forNumber(type_); + return result == null ? pl.leancode.patrol.contracts.Contracts.DartGroupEntry.GroupEntryType.UNRECOGNIZED : result; } /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @param value The enum numeric value on the wire for type to set. */ - @java.lang.Override - public pl.leancode.patrol.contracts.Contracts.DartTestCase getTests(int index) { - return tests_.get(index); + private void setTypeValue(int value) { + type_ = value; } /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @param value The type to set. */ - public pl.leancode.patrol.contracts.Contracts.DartTestCaseOrBuilder getTestsOrBuilder( - int index) { - return tests_.get(index); - } - private void ensureTestsIsMutable() { - com.google.protobuf.Internal.ProtobufList tmp = tests_; - if (!tmp.isModifiable()) { - tests_ = - com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp); - } - } + private void setType(pl.leancode.patrol.contracts.Contracts.DartGroupEntry.GroupEntryType value) { + type_ = value.getNumber(); - /** - * repeated .patrol.DartTestCase tests = 2; - */ - private void setTests( - int index, pl.leancode.patrol.contracts.Contracts.DartTestCase value) { - value.getClass(); - ensureTestsIsMutable(); - tests_.set(index, value); - } - /** - * repeated .patrol.DartTestCase tests = 2; - */ - private void addTests(pl.leancode.patrol.contracts.Contracts.DartTestCase value) { - value.getClass(); - ensureTestsIsMutable(); - tests_.add(value); - } - /** - * repeated .patrol.DartTestCase tests = 2; - */ - private void addTests( - int index, pl.leancode.patrol.contracts.Contracts.DartTestCase value) { - value.getClass(); - ensureTestsIsMutable(); - tests_.add(index, value); } /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; */ - private void addAllTests( - java.lang.Iterable values) { - ensureTestsIsMutable(); - com.google.protobuf.AbstractMessageLite.addAll( - values, tests_); - } - /** - * repeated .patrol.DartTestCase tests = 2; - */ - private void clearTests() { - tests_ = emptyProtobufList(); - } - /** - * repeated .patrol.DartTestCase tests = 2; - */ - private void removeTests(int index) { - ensureTestsIsMutable(); - tests_.remove(index); + private void clearType() { + + type_ = 0; } - public static final int GROUPS_FIELD_NUMBER = 3; - private com.google.protobuf.Internal.ProtobufList groups_; + public static final int ENTRIES_FIELD_NUMBER = 4; + private com.google.protobuf.Internal.ProtobufList entries_; /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ @java.lang.Override - public java.util.List getGroupsList() { - return groups_; + public java.util.List getEntriesList() { + return entries_; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public java.util.List - getGroupsOrBuilderList() { - return groups_; + public java.util.List + getEntriesOrBuilderList() { + return entries_; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ @java.lang.Override - public int getGroupsCount() { - return groups_.size(); + public int getEntriesCount() { + return entries_.size(); } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ @java.lang.Override - public pl.leancode.patrol.contracts.Contracts.DartTestGroup getGroups(int index) { - return groups_.get(index); + public pl.leancode.patrol.contracts.Contracts.DartGroupEntry getEntries(int index) { + return entries_.get(index); } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public pl.leancode.patrol.contracts.Contracts.DartTestGroupOrBuilder getGroupsOrBuilder( + public pl.leancode.patrol.contracts.Contracts.DartGroupEntryOrBuilder getEntriesOrBuilder( int index) { - return groups_.get(index); + return entries_.get(index); } - private void ensureGroupsIsMutable() { - com.google.protobuf.Internal.ProtobufList tmp = groups_; + private void ensureEntriesIsMutable() { + com.google.protobuf.Internal.ProtobufList tmp = entries_; if (!tmp.isModifiable()) { - groups_ = + entries_ = com.google.protobuf.GeneratedMessageLite.mutableCopy(tmp); } } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - private void setGroups( - int index, pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + private void setEntries( + int index, pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { value.getClass(); - ensureGroupsIsMutable(); - groups_.set(index, value); + ensureEntriesIsMutable(); + entries_.set(index, value); } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - private void addGroups(pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + private void addEntries(pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { value.getClass(); - ensureGroupsIsMutable(); - groups_.add(value); + ensureEntriesIsMutable(); + entries_.add(value); } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - private void addGroups( - int index, pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + private void addEntries( + int index, pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { value.getClass(); - ensureGroupsIsMutable(); - groups_.add(index, value); + ensureEntriesIsMutable(); + entries_.add(index, value); } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - private void addAllGroups( - java.lang.Iterable values) { - ensureGroupsIsMutable(); + private void addAllEntries( + java.lang.Iterable values) { + ensureEntriesIsMutable(); com.google.protobuf.AbstractMessageLite.addAll( - values, groups_); + values, entries_); } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - private void clearGroups() { - groups_ = emptyProtobufList(); + private void clearEntries() { + entries_ = emptyProtobufList(); } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - private void removeGroups(int index) { - ensureGroupsIsMutable(); - groups_.remove(index); + private void removeEntries(int index) { + ensureEntriesIsMutable(); + entries_.remove(index); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return com.google.protobuf.GeneratedMessageLite.parseFrom( DEFAULT_INSTANCE, data); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return com.google.protobuf.GeneratedMessageLite.parseFrom( DEFAULT_INSTANCE, data, extensionRegistry); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return com.google.protobuf.GeneratedMessageLite.parseFrom( DEFAULT_INSTANCE, data); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return com.google.protobuf.GeneratedMessageLite.parseFrom( DEFAULT_INSTANCE, data, extensionRegistry); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom(byte[] data) + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return com.google.protobuf.GeneratedMessageLite.parseFrom( DEFAULT_INSTANCE, data); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return com.google.protobuf.GeneratedMessageLite.parseFrom( DEFAULT_INSTANCE, data, extensionRegistry); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom(java.io.InputStream input) + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageLite.parseFrom( DEFAULT_INSTANCE, input); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -640,24 +675,24 @@ public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( DEFAULT_INSTANCE, input, extensionRegistry); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseDelimitedFrom(java.io.InputStream input) + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return parseDelimitedFrom(DEFAULT_INSTANCE, input); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseDelimitedFrom( + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return parseDelimitedFrom(DEFAULT_INSTANCE, input, extensionRegistry); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageLite.parseFrom( DEFAULT_INSTANCE, input); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -668,19 +703,19 @@ public static pl.leancode.patrol.contracts.Contracts.DartTestGroup parseFrom( public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } - public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.DartTestGroup prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.DartGroupEntry prototype) { + return DEFAULT_INSTANCE.createBuilder(prototype); } /** - * Protobuf type {@code patrol.DartTestGroup} + * Protobuf type {@code patrol.DartGroupEntry} */ public static final class Builder extends com.google.protobuf.GeneratedMessageLite.Builder< - pl.leancode.patrol.contracts.Contracts.DartTestGroup, Builder> implements - // @@protoc_insertion_point(builder_implements:patrol.DartTestGroup) - pl.leancode.patrol.contracts.Contracts.DartTestGroupOrBuilder { - // Construct using pl.leancode.patrol.contracts.Contracts.DartTestGroup.newBuilder() + pl.leancode.patrol.contracts.Contracts.DartGroupEntry, Builder> implements + // @@protoc_insertion_point(builder_implements:patrol.DartGroupEntry) + pl.leancode.patrol.contracts.Contracts.DartGroupEntryOrBuilder { + // Construct using pl.leancode.patrol.contracts.Contracts.DartGroupEntry.newBuilder() private Builder() { super(DEFAULT_INSTANCE); } @@ -736,210 +771,154 @@ public Builder setNameBytes( } /** - * repeated .patrol.DartTestCase tests = 2; - */ - @java.lang.Override - public java.util.List getTestsList() { - return java.util.Collections.unmodifiableList( - instance.getTestsList()); - } - /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @return The enum numeric value on the wire for type. */ @java.lang.Override - public int getTestsCount() { - return instance.getTestsCount(); - }/** - * repeated .patrol.DartTestCase tests = 2; - */ - @java.lang.Override - public pl.leancode.patrol.contracts.Contracts.DartTestCase getTests(int index) { - return instance.getTests(index); - } - /** - * repeated .patrol.DartTestCase tests = 2; - */ - public Builder setTests( - int index, pl.leancode.patrol.contracts.Contracts.DartTestCase value) { - copyOnWrite(); - instance.setTests(index, value); - return this; - } - /** - * repeated .patrol.DartTestCase tests = 2; - */ - public Builder setTests( - int index, pl.leancode.patrol.contracts.Contracts.DartTestCase.Builder builderForValue) { - copyOnWrite(); - instance.setTests(index, - builderForValue.build()); - return this; - } - /** - * repeated .patrol.DartTestCase tests = 2; - */ - public Builder addTests(pl.leancode.patrol.contracts.Contracts.DartTestCase value) { - copyOnWrite(); - instance.addTests(value); - return this; - } - /** - * repeated .patrol.DartTestCase tests = 2; - */ - public Builder addTests( - int index, pl.leancode.patrol.contracts.Contracts.DartTestCase value) { - copyOnWrite(); - instance.addTests(index, value); - return this; - } - /** - * repeated .patrol.DartTestCase tests = 2; - */ - public Builder addTests( - pl.leancode.patrol.contracts.Contracts.DartTestCase.Builder builderForValue) { - copyOnWrite(); - instance.addTests(builderForValue.build()); - return this; + public int getTypeValue() { + return instance.getTypeValue(); } /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @param value The type to set. + * @return This builder for chaining. */ - public Builder addTests( - int index, pl.leancode.patrol.contracts.Contracts.DartTestCase.Builder builderForValue) { + public Builder setTypeValue(int value) { copyOnWrite(); - instance.addTests(index, - builderForValue.build()); + instance.setTypeValue(value); return this; } /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @return The type. */ - public Builder addAllTests( - java.lang.Iterable values) { - copyOnWrite(); - instance.addAllTests(values); - return this; + @java.lang.Override + public pl.leancode.patrol.contracts.Contracts.DartGroupEntry.GroupEntryType getType() { + return instance.getType(); } /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @param value The enum numeric value on the wire for type to set. + * @return This builder for chaining. */ - public Builder clearTests() { + public Builder setType(pl.leancode.patrol.contracts.Contracts.DartGroupEntry.GroupEntryType value) { copyOnWrite(); - instance.clearTests(); + instance.setType(value); return this; } /** - * repeated .patrol.DartTestCase tests = 2; + * .patrol.DartGroupEntry.GroupEntryType type = 3; + * @return This builder for chaining. */ - public Builder removeTests(int index) { + public Builder clearType() { copyOnWrite(); - instance.removeTests(index); + instance.clearType(); return this; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ @java.lang.Override - public java.util.List getGroupsList() { + public java.util.List getEntriesList() { return java.util.Collections.unmodifiableList( - instance.getGroupsList()); + instance.getEntriesList()); } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ @java.lang.Override - public int getGroupsCount() { - return instance.getGroupsCount(); + public int getEntriesCount() { + return instance.getEntriesCount(); }/** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ @java.lang.Override - public pl.leancode.patrol.contracts.Contracts.DartTestGroup getGroups(int index) { - return instance.getGroups(index); + public pl.leancode.patrol.contracts.Contracts.DartGroupEntry getEntries(int index) { + return instance.getEntries(index); } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public Builder setGroups( - int index, pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + public Builder setEntries( + int index, pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { copyOnWrite(); - instance.setGroups(index, value); + instance.setEntries(index, value); return this; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public Builder setGroups( - int index, pl.leancode.patrol.contracts.Contracts.DartTestGroup.Builder builderForValue) { + public Builder setEntries( + int index, pl.leancode.patrol.contracts.Contracts.DartGroupEntry.Builder builderForValue) { copyOnWrite(); - instance.setGroups(index, + instance.setEntries(index, builderForValue.build()); return this; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public Builder addGroups(pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + public Builder addEntries(pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { copyOnWrite(); - instance.addGroups(value); + instance.addEntries(value); return this; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public Builder addGroups( - int index, pl.leancode.patrol.contracts.Contracts.DartTestGroup value) { + public Builder addEntries( + int index, pl.leancode.patrol.contracts.Contracts.DartGroupEntry value) { copyOnWrite(); - instance.addGroups(index, value); + instance.addEntries(index, value); return this; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public Builder addGroups( - pl.leancode.patrol.contracts.Contracts.DartTestGroup.Builder builderForValue) { + public Builder addEntries( + pl.leancode.patrol.contracts.Contracts.DartGroupEntry.Builder builderForValue) { copyOnWrite(); - instance.addGroups(builderForValue.build()); + instance.addEntries(builderForValue.build()); return this; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public Builder addGroups( - int index, pl.leancode.patrol.contracts.Contracts.DartTestGroup.Builder builderForValue) { + public Builder addEntries( + int index, pl.leancode.patrol.contracts.Contracts.DartGroupEntry.Builder builderForValue) { copyOnWrite(); - instance.addGroups(index, + instance.addEntries(index, builderForValue.build()); return this; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public Builder addAllGroups( - java.lang.Iterable values) { + public Builder addAllEntries( + java.lang.Iterable values) { copyOnWrite(); - instance.addAllGroups(values); + instance.addAllEntries(values); return this; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public Builder clearGroups() { + public Builder clearEntries() { copyOnWrite(); - instance.clearGroups(); + instance.clearEntries(); return this; } /** - * repeated .patrol.DartTestGroup groups = 3; + * repeated .patrol.DartGroupEntry entries = 4; */ - public Builder removeGroups(int index) { + public Builder removeEntries(int index) { copyOnWrite(); - instance.removeGroups(index); + instance.removeEntries(index); return this; } - // @@protoc_insertion_point(builder_scope:patrol.DartTestGroup) + // @@protoc_insertion_point(builder_scope:patrol.DartGroupEntry) } @java.lang.Override @java.lang.SuppressWarnings({"unchecked", "fallthrough"}) @@ -948,7 +927,7 @@ protected final java.lang.Object dynamicMethod( java.lang.Object arg0, java.lang.Object arg1) { switch (method) { case NEW_MUTABLE_INSTANCE: { - return new pl.leancode.patrol.contracts.Contracts.DartTestGroup(); + return new pl.leancode.patrol.contracts.Contracts.DartGroupEntry(); } case NEW_BUILDER: { return new Builder(); @@ -956,14 +935,13 @@ protected final java.lang.Object dynamicMethod( case BUILD_MESSAGE_INFO: { java.lang.Object[] objects = new java.lang.Object[] { "name_", - "tests_", - pl.leancode.patrol.contracts.Contracts.DartTestCase.class, - "groups_", - pl.leancode.patrol.contracts.Contracts.DartTestGroup.class, + "type_", + "entries_", + pl.leancode.patrol.contracts.Contracts.DartGroupEntry.class, }; java.lang.String info = - "\u0000\u0003\u0000\u0000\u0001\u0003\u0003\u0000\u0002\u0000\u0001\u0208\u0002\u001b" + - "\u0003\u001b"; + "\u0000\u0003\u0000\u0000\u0001\u0004\u0003\u0000\u0001\u0000\u0001\u0208\u0003\f" + + "\u0004\u001b"; return newMessageInfo(DEFAULT_INSTANCE, info, objects); } // fall through @@ -971,13 +949,13 @@ protected final java.lang.Object dynamicMethod( return DEFAULT_INSTANCE; } case GET_PARSER: { - com.google.protobuf.Parser parser = PARSER; + com.google.protobuf.Parser parser = PARSER; if (parser == null) { - synchronized (pl.leancode.patrol.contracts.Contracts.DartTestGroup.class) { + synchronized (pl.leancode.patrol.contracts.Contracts.DartGroupEntry.class) { parser = PARSER; if (parser == null) { parser = - new DefaultInstanceBasedParser( + new DefaultInstanceBasedParser( DEFAULT_INSTANCE); PARSER = parser; } @@ -996,318 +974,24 @@ protected final java.lang.Object dynamicMethod( } - // @@protoc_insertion_point(class_scope:patrol.DartTestGroup) - private static final pl.leancode.patrol.contracts.Contracts.DartTestGroup DEFAULT_INSTANCE; + // @@protoc_insertion_point(class_scope:patrol.DartGroupEntry) + private static final pl.leancode.patrol.contracts.Contracts.DartGroupEntry DEFAULT_INSTANCE; static { - DartTestGroup defaultInstance = new DartTestGroup(); + DartGroupEntry defaultInstance = new DartGroupEntry(); // New instances are implicitly immutable so no need to make // immutable. DEFAULT_INSTANCE = defaultInstance; com.google.protobuf.GeneratedMessageLite.registerDefaultInstance( - DartTestGroup.class, defaultInstance); + DartGroupEntry.class, defaultInstance); } - public static pl.leancode.patrol.contracts.Contracts.DartTestGroup getDefaultInstance() { + public static pl.leancode.patrol.contracts.Contracts.DartGroupEntry getDefaultInstance() { return DEFAULT_INSTANCE; } - private static volatile com.google.protobuf.Parser PARSER; + private static volatile com.google.protobuf.Parser PARSER; - public static com.google.protobuf.Parser parser() { - return DEFAULT_INSTANCE.getParserForType(); - } - } - - public interface DartTestCaseOrBuilder extends - // @@protoc_insertion_point(interface_extends:patrol.DartTestCase) - com.google.protobuf.MessageLiteOrBuilder { - - /** - * string name = 1; - * @return The name. - */ - java.lang.String getName(); - /** - * string name = 1; - * @return The bytes for name. - */ - com.google.protobuf.ByteString - getNameBytes(); - } - /** - * Protobuf type {@code patrol.DartTestCase} - */ - public static final class DartTestCase extends - com.google.protobuf.GeneratedMessageLite< - DartTestCase, DartTestCase.Builder> implements - // @@protoc_insertion_point(message_implements:patrol.DartTestCase) - DartTestCaseOrBuilder { - private DartTestCase() { - name_ = ""; - } - public static final int NAME_FIELD_NUMBER = 1; - private java.lang.String name_; - /** - * string name = 1; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - return name_; - } - /** - * string name = 1; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - return com.google.protobuf.ByteString.copyFromUtf8(name_); - } - /** - * string name = 1; - * @param value The name to set. - */ - private void setName( - java.lang.String value) { - java.lang.Class valueClass = value.getClass(); - - name_ = value; - } - /** - * string name = 1; - */ - private void clearName() { - - name_ = getDefaultInstance().getName(); - } - /** - * string name = 1; - * @param value The bytes for name to set. - */ - private void setNameBytes( - com.google.protobuf.ByteString value) { - checkByteStringIsUtf8(value); - name_ = value.toStringUtf8(); - - } - - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom( - java.nio.ByteBuffer data) - throws com.google.protobuf.InvalidProtocolBufferException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, data); - } - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom( - java.nio.ByteBuffer data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, data, extensionRegistry); - } - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, data); - } - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, data, extensionRegistry); - } - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, data); - } - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, data, extensionRegistry); - } - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom(java.io.InputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, input); - } - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, input, extensionRegistry); - } - - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return parseDelimitedFrom(DEFAULT_INSTANCE, input); - } - - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return parseDelimitedFrom(DEFAULT_INSTANCE, input, extensionRegistry); - } - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, input); - } - public static pl.leancode.patrol.contracts.Contracts.DartTestCase parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return com.google.protobuf.GeneratedMessageLite.parseFrom( - DEFAULT_INSTANCE, input, extensionRegistry); - } - - public static Builder newBuilder() { - return (Builder) DEFAULT_INSTANCE.createBuilder(); - } - public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.DartTestCase prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); - } - - /** - * Protobuf type {@code patrol.DartTestCase} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessageLite.Builder< - pl.leancode.patrol.contracts.Contracts.DartTestCase, Builder> implements - // @@protoc_insertion_point(builder_implements:patrol.DartTestCase) - pl.leancode.patrol.contracts.Contracts.DartTestCaseOrBuilder { - // Construct using pl.leancode.patrol.contracts.Contracts.DartTestCase.newBuilder() - private Builder() { - super(DEFAULT_INSTANCE); - } - - - /** - * string name = 1; - * @return The name. - */ - @java.lang.Override - public java.lang.String getName() { - return instance.getName(); - } - /** - * string name = 1; - * @return The bytes for name. - */ - @java.lang.Override - public com.google.protobuf.ByteString - getNameBytes() { - return instance.getNameBytes(); - } - /** - * string name = 1; - * @param value The name to set. - * @return This builder for chaining. - */ - public Builder setName( - java.lang.String value) { - copyOnWrite(); - instance.setName(value); - return this; - } - /** - * string name = 1; - * @return This builder for chaining. - */ - public Builder clearName() { - copyOnWrite(); - instance.clearName(); - return this; - } - /** - * string name = 1; - * @param value The bytes for name to set. - * @return This builder for chaining. - */ - public Builder setNameBytes( - com.google.protobuf.ByteString value) { - copyOnWrite(); - instance.setNameBytes(value); - return this; - } - - // @@protoc_insertion_point(builder_scope:patrol.DartTestCase) - } - @java.lang.Override - @java.lang.SuppressWarnings({"unchecked", "fallthrough"}) - protected final java.lang.Object dynamicMethod( - com.google.protobuf.GeneratedMessageLite.MethodToInvoke method, - java.lang.Object arg0, java.lang.Object arg1) { - switch (method) { - case NEW_MUTABLE_INSTANCE: { - return new pl.leancode.patrol.contracts.Contracts.DartTestCase(); - } - case NEW_BUILDER: { - return new Builder(); - } - case BUILD_MESSAGE_INFO: { - java.lang.Object[] objects = new java.lang.Object[] { - "name_", - }; - java.lang.String info = - "\u0000\u0001\u0000\u0000\u0001\u0001\u0001\u0000\u0000\u0000\u0001\u0208"; - return newMessageInfo(DEFAULT_INSTANCE, info, objects); - } - // fall through - case GET_DEFAULT_INSTANCE: { - return DEFAULT_INSTANCE; - } - case GET_PARSER: { - com.google.protobuf.Parser parser = PARSER; - if (parser == null) { - synchronized (pl.leancode.patrol.contracts.Contracts.DartTestCase.class) { - parser = PARSER; - if (parser == null) { - parser = - new DefaultInstanceBasedParser( - DEFAULT_INSTANCE); - PARSER = parser; - } - } - } - return parser; - } - case GET_MEMOIZED_IS_INITIALIZED: { - return (byte) 1; - } - case SET_MEMOIZED_IS_INITIALIZED: { - return null; - } - } - throw new UnsupportedOperationException(); - } - - - // @@protoc_insertion_point(class_scope:patrol.DartTestCase) - private static final pl.leancode.patrol.contracts.Contracts.DartTestCase DEFAULT_INSTANCE; - static { - DartTestCase defaultInstance = new DartTestCase(); - // New instances are implicitly immutable so no need to make - // immutable. - DEFAULT_INSTANCE = defaultInstance; - com.google.protobuf.GeneratedMessageLite.registerDefaultInstance( - DartTestCase.class, defaultInstance); - } - - public static pl.leancode.patrol.contracts.Contracts.DartTestCase getDefaultInstance() { - return DEFAULT_INSTANCE; - } - - private static volatile com.google.protobuf.Parser PARSER; - - public static com.google.protobuf.Parser parser() { + public static com.google.protobuf.Parser parser() { return DEFAULT_INSTANCE.getParserForType(); } } @@ -1466,7 +1150,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.RunDartTestRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -1925,7 +1609,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.RunDartTestResponse prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -2248,7 +1932,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.ConfigureRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -2521,7 +2205,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.OpenAppRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -2910,7 +2594,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.TapOnNotificationRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -3202,7 +2886,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.Empty prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -3392,7 +3076,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.OpenQuickSettingsRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -3634,7 +3318,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.DarkModeRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -3812,6 +3496,7 @@ public static final class GetNativeViewsRequest extends private GetNativeViewsRequest() { appId_ = ""; } + private int bitField0_; public static final int SELECTOR_FIELD_NUMBER = 1; private pl.leancode.patrol.contracts.Contracts.Selector selector_; /** @@ -3819,7 +3504,7 @@ private GetNativeViewsRequest() { */ @java.lang.Override public boolean hasSelector() { - return selector_ != null; + return ((bitField0_ & 0x00000001) != 0); } /** * .patrol.Selector selector = 1; @@ -3834,7 +3519,7 @@ public pl.leancode.patrol.contracts.Contracts.Selector getSelector() { private void setSelector(pl.leancode.patrol.contracts.Contracts.Selector value) { value.getClass(); selector_ = value; - + bitField0_ |= 0x00000001; } /** * .patrol.Selector selector = 1; @@ -3849,13 +3534,13 @@ private void mergeSelector(pl.leancode.patrol.contracts.Contracts.Selector value } else { selector_ = value; } - + bitField0_ |= 0x00000001; } /** * .patrol.Selector selector = 1; */ private void clearSelector() { selector_ = null; - + bitField0_ = (bitField0_ & ~0x00000001); } public static final int APPID_FIELD_NUMBER = 2; @@ -3985,7 +3670,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.GetNativeViewsRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -4114,12 +3799,13 @@ protected final java.lang.Object dynamicMethod( } case BUILD_MESSAGE_INFO: { java.lang.Object[] objects = new java.lang.Object[] { + "bitField0_", "selector_", "appId_", }; java.lang.String info = - "\u0000\u0002\u0000\u0000\u0001\u0002\u0002\u0000\u0000\u0000\u0001\t\u0002\u0208" + - ""; + "\u0000\u0002\u0000\u0001\u0001\u0002\u0002\u0000\u0000\u0000\u0001\u1009\u0000\u0002" + + "\u0208"; return newMessageInfo(DEFAULT_INSTANCE, info, objects); } // fall through @@ -4377,7 +4063,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.GetNativeViewsResponse prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -4665,7 +4351,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.GetNotificationsRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -4956,7 +4642,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.GetNotificationsResponse prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -5188,6 +4874,7 @@ public static final class TapRequest extends private TapRequest() { appId_ = ""; } + private int bitField0_; public static final int SELECTOR_FIELD_NUMBER = 1; private pl.leancode.patrol.contracts.Contracts.Selector selector_; /** @@ -5195,7 +4882,7 @@ private TapRequest() { */ @java.lang.Override public boolean hasSelector() { - return selector_ != null; + return ((bitField0_ & 0x00000001) != 0); } /** * .patrol.Selector selector = 1; @@ -5210,7 +4897,7 @@ public pl.leancode.patrol.contracts.Contracts.Selector getSelector() { private void setSelector(pl.leancode.patrol.contracts.Contracts.Selector value) { value.getClass(); selector_ = value; - + bitField0_ |= 0x00000001; } /** * .patrol.Selector selector = 1; @@ -5225,13 +4912,13 @@ private void mergeSelector(pl.leancode.patrol.contracts.Contracts.Selector value } else { selector_ = value; } - + bitField0_ |= 0x00000001; } /** * .patrol.Selector selector = 1; */ private void clearSelector() { selector_ = null; - + bitField0_ = (bitField0_ & ~0x00000001); } public static final int APPID_FIELD_NUMBER = 2; @@ -5361,7 +5048,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.TapRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -5490,12 +5177,13 @@ protected final java.lang.Object dynamicMethod( } case BUILD_MESSAGE_INFO: { java.lang.Object[] objects = new java.lang.Object[] { + "bitField0_", "selector_", "appId_", }; java.lang.String info = - "\u0000\u0002\u0000\u0000\u0001\u0002\u0002\u0000\u0000\u0000\u0001\t\u0002\u0208" + - ""; + "\u0000\u0002\u0000\u0001\u0001\u0002\u0002\u0000\u0000\u0000\u0001\u1009\u0000\u0002" + + "\u0208"; return newMessageInfo(DEFAULT_INSTANCE, info, objects); } // fall through @@ -5631,26 +5319,10 @@ private EnterTextRequest() { public enum KeyboardBehavior implements com.google.protobuf.Internal.EnumLite { /** - *
-       * The default keyboard behavior.
-       *
-       * Keyboard will be shown when entering text starts, and will be
-       * automatically dismissed afterwards.
-       * 
- * * SHOW_AND_DISMISS = 0; */ SHOW_AND_DISMISS(0), /** - *
-       * The alternative keyboard behavior.
-       *
-       * On Android, no keyboard will be shown at all. The text will simply appear
-       * inside the TextField.
-       *
-       * On iOS, the keyboard will not be dismissed after entering text.
-       * 
- * * ALTERNATIVE = 1; */ ALTERNATIVE(1), @@ -5658,26 +5330,10 @@ public enum KeyboardBehavior ; /** - *
-       * The default keyboard behavior.
-       *
-       * Keyboard will be shown when entering text starts, and will be
-       * automatically dismissed afterwards.
-       * 
- * * SHOW_AND_DISMISS = 0; */ public static final int SHOW_AND_DISMISS_VALUE = 0; /** - *
-       * The alternative keyboard behavior.
-       *
-       * On Android, no keyboard will be shown at all. The text will simply appear
-       * inside the TextField.
-       *
-       * On iOS, the keyboard will not be dismissed after entering text.
-       * 
- * * ALTERNATIVE = 1; */ public static final int ALTERNATIVE_VALUE = 1; @@ -6093,7 +5749,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.EnterTextRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -6744,7 +6400,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.SwipeRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -7068,6 +6724,7 @@ public static final class WaitUntilVisibleRequest extends private WaitUntilVisibleRequest() { appId_ = ""; } + private int bitField0_; public static final int SELECTOR_FIELD_NUMBER = 1; private pl.leancode.patrol.contracts.Contracts.Selector selector_; /** @@ -7075,7 +6732,7 @@ private WaitUntilVisibleRequest() { */ @java.lang.Override public boolean hasSelector() { - return selector_ != null; + return ((bitField0_ & 0x00000001) != 0); } /** * .patrol.Selector selector = 1; @@ -7090,7 +6747,7 @@ public pl.leancode.patrol.contracts.Contracts.Selector getSelector() { private void setSelector(pl.leancode.patrol.contracts.Contracts.Selector value) { value.getClass(); selector_ = value; - + bitField0_ |= 0x00000001; } /** * .patrol.Selector selector = 1; @@ -7105,13 +6762,13 @@ private void mergeSelector(pl.leancode.patrol.contracts.Contracts.Selector value } else { selector_ = value; } - + bitField0_ |= 0x00000001; } /** * .patrol.Selector selector = 1; */ private void clearSelector() { selector_ = null; - + bitField0_ = (bitField0_ & ~0x00000001); } public static final int APPID_FIELD_NUMBER = 2; @@ -7241,7 +6898,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.WaitUntilVisibleRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -7370,12 +7027,13 @@ protected final java.lang.Object dynamicMethod( } case BUILD_MESSAGE_INFO: { java.lang.Object[] objects = new java.lang.Object[] { + "bitField0_", "selector_", "appId_", }; java.lang.String info = - "\u0000\u0002\u0000\u0000\u0001\u0002\u0002\u0000\u0000\u0000\u0001\t\u0002\u0208" + - ""; + "\u0000\u0002\u0000\u0001\u0001\u0002\u0002\u0000\u0000\u0000\u0001\u1009\u0000\u0002" + + "\u0208"; return newMessageInfo(DEFAULT_INSTANCE, info, objects); } // fall through @@ -7675,7 +7333,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.HandlePermissionRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -8048,7 +7706,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.SetLocationAccuracyRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -8311,7 +7969,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.PermissionDialogVisibleRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -8556,7 +8214,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.PermissionDialogVisibleResponse prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -9562,7 +9220,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.Selector prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -10893,7 +10551,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.NativeView prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -11783,7 +11441,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.Notification prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** @@ -12312,7 +11970,7 @@ public static Builder newBuilder() { return (Builder) DEFAULT_INSTANCE.createBuilder(); } public static Builder newBuilder(pl.leancode.patrol.contracts.Contracts.SubmitTestResultsRequest prototype) { - return (Builder) DEFAULT_INSTANCE.createBuilder(prototype); + return DEFAULT_INSTANCE.createBuilder(prototype); } /** diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/DartGroupEntryKt.kt b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/DartGroupEntryKt.kt new file mode 100644 index 000000000..e3f6f7fab --- /dev/null +++ b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/DartGroupEntryKt.kt @@ -0,0 +1,145 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: contracts.proto + +// Generated files should ignore deprecation warnings +@file:Suppress("DEPRECATION") +package pl.leancode.patrol.contracts; + +@kotlin.jvm.JvmName("-initializedartGroupEntry") +public inline fun dartGroupEntry(block: pl.leancode.patrol.contracts.DartGroupEntryKt.Dsl.() -> kotlin.Unit): pl.leancode.patrol.contracts.Contracts.DartGroupEntry = + pl.leancode.patrol.contracts.DartGroupEntryKt.Dsl._create(pl.leancode.patrol.contracts.Contracts.DartGroupEntry.newBuilder()).apply { block() }._build() +/** + * Protobuf type `patrol.DartGroupEntry` + */ +public object DartGroupEntryKt { + @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class) + @com.google.protobuf.kotlin.ProtoDslMarker + public class Dsl private constructor( + private val _builder: pl.leancode.patrol.contracts.Contracts.DartGroupEntry.Builder + ) { + public companion object { + @kotlin.jvm.JvmSynthetic + @kotlin.PublishedApi + internal fun _create(builder: pl.leancode.patrol.contracts.Contracts.DartGroupEntry.Builder): Dsl = Dsl(builder) + } + + @kotlin.jvm.JvmSynthetic + @kotlin.PublishedApi + internal fun _build(): pl.leancode.patrol.contracts.Contracts.DartGroupEntry = _builder.build() + + /** + * `string name = 1;` + */ + public var name: kotlin.String + @JvmName("getName") + get() = _builder.getName() + @JvmName("setName") + set(value) { + _builder.setName(value) + } + /** + * `string name = 1;` + */ + public fun clearName() { + _builder.clearName() + } + + /** + * `.patrol.DartGroupEntry.GroupEntryType type = 3;` + */ + public var type: pl.leancode.patrol.contracts.Contracts.DartGroupEntry.GroupEntryType + @JvmName("getType") + get() = _builder.getType() + @JvmName("setType") + set(value) { + _builder.setType(value) + } + public var typeValue: kotlin.Int + @JvmName("getTypeValue") + get() = _builder.getTypeValue() + @JvmName("setTypeValue") + set(value) { + _builder.setTypeValue(value) + } + /** + * `.patrol.DartGroupEntry.GroupEntryType type = 3;` + */ + public fun clearType() { + _builder.clearType() + } + + /** + * An uninstantiable, behaviorless type to represent the field in + * generics. + */ + @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class) + public class EntriesProxy private constructor() : com.google.protobuf.kotlin.DslProxy() + /** + * `repeated .patrol.DartGroupEntry entries = 4;` + */ + public val entries: com.google.protobuf.kotlin.DslList + @kotlin.jvm.JvmSynthetic + get() = com.google.protobuf.kotlin.DslList( + _builder.getEntriesList() + ) + /** + * `repeated .patrol.DartGroupEntry entries = 4;` + * @param value The entries to add. + */ + @kotlin.jvm.JvmSynthetic + @kotlin.jvm.JvmName("addEntries") + public fun com.google.protobuf.kotlin.DslList.add(value: pl.leancode.patrol.contracts.Contracts.DartGroupEntry) { + _builder.addEntries(value) + } + /** + * `repeated .patrol.DartGroupEntry entries = 4;` + * @param value The entries to add. + */ + @kotlin.jvm.JvmSynthetic + @kotlin.jvm.JvmName("plusAssignEntries") + @Suppress("NOTHING_TO_INLINE") + public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(value: pl.leancode.patrol.contracts.Contracts.DartGroupEntry) { + add(value) + } + /** + * `repeated .patrol.DartGroupEntry entries = 4;` + * @param values The entries to add. + */ + @kotlin.jvm.JvmSynthetic + @kotlin.jvm.JvmName("addAllEntries") + public fun com.google.protobuf.kotlin.DslList.addAll(values: kotlin.collections.Iterable) { + _builder.addAllEntries(values) + } + /** + * `repeated .patrol.DartGroupEntry entries = 4;` + * @param values The entries to add. + */ + @kotlin.jvm.JvmSynthetic + @kotlin.jvm.JvmName("plusAssignAllEntries") + @Suppress("NOTHING_TO_INLINE") + public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(values: kotlin.collections.Iterable) { + addAll(values) + } + /** + * `repeated .patrol.DartGroupEntry entries = 4;` + * @param index The index to set the value at. + * @param value The entries to set. + */ + @kotlin.jvm.JvmSynthetic + @kotlin.jvm.JvmName("setEntries") + public operator fun com.google.protobuf.kotlin.DslList.set(index: kotlin.Int, value: pl.leancode.patrol.contracts.Contracts.DartGroupEntry) { + _builder.setEntries(index, value) + } + /** + * `repeated .patrol.DartGroupEntry entries = 4;` + */ + @kotlin.jvm.JvmSynthetic + @kotlin.jvm.JvmName("clearEntries") + public fun com.google.protobuf.kotlin.DslList.clear() { + _builder.clearEntries() + } + } +} +public inline fun pl.leancode.patrol.contracts.Contracts.DartGroupEntry.copy(block: pl.leancode.patrol.contracts.DartGroupEntryKt.Dsl.() -> kotlin.Unit): pl.leancode.patrol.contracts.Contracts.DartGroupEntry = + pl.leancode.patrol.contracts.DartGroupEntryKt.Dsl._create(this.toBuilder()).apply { block() }._build() + diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/DartTestCaseKt.kt b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/DartTestCaseKt.kt deleted file mode 100644 index d9213b71c..000000000 --- a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/DartTestCaseKt.kt +++ /dev/null @@ -1,50 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: contracts.proto - -// Generated files should ignore deprecation warnings -@file:Suppress("DEPRECATION") -package pl.leancode.patrol.contracts; - -@kotlin.jvm.JvmName("-initializedartTestCase") -public inline fun dartTestCase(block: pl.leancode.patrol.contracts.DartTestCaseKt.Dsl.() -> kotlin.Unit): pl.leancode.patrol.contracts.Contracts.DartTestCase = - pl.leancode.patrol.contracts.DartTestCaseKt.Dsl._create(pl.leancode.patrol.contracts.Contracts.DartTestCase.newBuilder()).apply { block() }._build() -/** - * Protobuf type `patrol.DartTestCase` - */ -public object DartTestCaseKt { - @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class) - @com.google.protobuf.kotlin.ProtoDslMarker - public class Dsl private constructor( - private val _builder: pl.leancode.patrol.contracts.Contracts.DartTestCase.Builder - ) { - public companion object { - @kotlin.jvm.JvmSynthetic - @kotlin.PublishedApi - internal fun _create(builder: pl.leancode.patrol.contracts.Contracts.DartTestCase.Builder): Dsl = Dsl(builder) - } - - @kotlin.jvm.JvmSynthetic - @kotlin.PublishedApi - internal fun _build(): pl.leancode.patrol.contracts.Contracts.DartTestCase = _builder.build() - - /** - * `string name = 1;` - */ - public var name: kotlin.String - @JvmName("getName") - get() = _builder.getName() - @JvmName("setName") - set(value) { - _builder.setName(value) - } - /** - * `string name = 1;` - */ - public fun clearName() { - _builder.clearName() - } - } -} -public inline fun pl.leancode.patrol.contracts.Contracts.DartTestCase.copy(block: pl.leancode.patrol.contracts.DartTestCaseKt.Dsl.() -> kotlin.Unit): pl.leancode.patrol.contracts.Contracts.DartTestCase = - pl.leancode.patrol.contracts.DartTestCaseKt.Dsl._create(this.toBuilder()).apply { block() }._build() - diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/DartTestGroupKt.kt b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/DartTestGroupKt.kt deleted file mode 100644 index 2bf1e489c..000000000 --- a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/DartTestGroupKt.kt +++ /dev/null @@ -1,192 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: contracts.proto - -// Generated files should ignore deprecation warnings -@file:Suppress("DEPRECATION") -package pl.leancode.patrol.contracts; - -@kotlin.jvm.JvmName("-initializedartTestGroup") -public inline fun dartTestGroup(block: pl.leancode.patrol.contracts.DartTestGroupKt.Dsl.() -> kotlin.Unit): pl.leancode.patrol.contracts.Contracts.DartTestGroup = - pl.leancode.patrol.contracts.DartTestGroupKt.Dsl._create(pl.leancode.patrol.contracts.Contracts.DartTestGroup.newBuilder()).apply { block() }._build() -/** - * Protobuf type `patrol.DartTestGroup` - */ -public object DartTestGroupKt { - @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class) - @com.google.protobuf.kotlin.ProtoDslMarker - public class Dsl private constructor( - private val _builder: pl.leancode.patrol.contracts.Contracts.DartTestGroup.Builder - ) { - public companion object { - @kotlin.jvm.JvmSynthetic - @kotlin.PublishedApi - internal fun _create(builder: pl.leancode.patrol.contracts.Contracts.DartTestGroup.Builder): Dsl = Dsl(builder) - } - - @kotlin.jvm.JvmSynthetic - @kotlin.PublishedApi - internal fun _build(): pl.leancode.patrol.contracts.Contracts.DartTestGroup = _builder.build() - - /** - * `string name = 1;` - */ - public var name: kotlin.String - @JvmName("getName") - get() = _builder.getName() - @JvmName("setName") - set(value) { - _builder.setName(value) - } - /** - * `string name = 1;` - */ - public fun clearName() { - _builder.clearName() - } - - /** - * An uninstantiable, behaviorless type to represent the field in - * generics. - */ - @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class) - public class TestsProxy private constructor() : com.google.protobuf.kotlin.DslProxy() - /** - * `repeated .patrol.DartTestCase tests = 2;` - */ - public val tests: com.google.protobuf.kotlin.DslList - @kotlin.jvm.JvmSynthetic - get() = com.google.protobuf.kotlin.DslList( - _builder.getTestsList() - ) - /** - * `repeated .patrol.DartTestCase tests = 2;` - * @param value The tests to add. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("addTests") - public fun com.google.protobuf.kotlin.DslList.add(value: pl.leancode.patrol.contracts.Contracts.DartTestCase) { - _builder.addTests(value) - } - /** - * `repeated .patrol.DartTestCase tests = 2;` - * @param value The tests to add. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("plusAssignTests") - @Suppress("NOTHING_TO_INLINE") - public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(value: pl.leancode.patrol.contracts.Contracts.DartTestCase) { - add(value) - } - /** - * `repeated .patrol.DartTestCase tests = 2;` - * @param values The tests to add. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("addAllTests") - public fun com.google.protobuf.kotlin.DslList.addAll(values: kotlin.collections.Iterable) { - _builder.addAllTests(values) - } - /** - * `repeated .patrol.DartTestCase tests = 2;` - * @param values The tests to add. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("plusAssignAllTests") - @Suppress("NOTHING_TO_INLINE") - public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(values: kotlin.collections.Iterable) { - addAll(values) - } - /** - * `repeated .patrol.DartTestCase tests = 2;` - * @param index The index to set the value at. - * @param value The tests to set. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("setTests") - public operator fun com.google.protobuf.kotlin.DslList.set(index: kotlin.Int, value: pl.leancode.patrol.contracts.Contracts.DartTestCase) { - _builder.setTests(index, value) - } - /** - * `repeated .patrol.DartTestCase tests = 2;` - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("clearTests") - public fun com.google.protobuf.kotlin.DslList.clear() { - _builder.clearTests() - } - - /** - * An uninstantiable, behaviorless type to represent the field in - * generics. - */ - @kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class) - public class GroupsProxy private constructor() : com.google.protobuf.kotlin.DslProxy() - /** - * `repeated .patrol.DartTestGroup groups = 3;` - */ - public val groups: com.google.protobuf.kotlin.DslList - @kotlin.jvm.JvmSynthetic - get() = com.google.protobuf.kotlin.DslList( - _builder.getGroupsList() - ) - /** - * `repeated .patrol.DartTestGroup groups = 3;` - * @param value The groups to add. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("addGroups") - public fun com.google.protobuf.kotlin.DslList.add(value: pl.leancode.patrol.contracts.Contracts.DartTestGroup) { - _builder.addGroups(value) - } - /** - * `repeated .patrol.DartTestGroup groups = 3;` - * @param value The groups to add. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("plusAssignGroups") - @Suppress("NOTHING_TO_INLINE") - public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(value: pl.leancode.patrol.contracts.Contracts.DartTestGroup) { - add(value) - } - /** - * `repeated .patrol.DartTestGroup groups = 3;` - * @param values The groups to add. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("addAllGroups") - public fun com.google.protobuf.kotlin.DslList.addAll(values: kotlin.collections.Iterable) { - _builder.addAllGroups(values) - } - /** - * `repeated .patrol.DartTestGroup groups = 3;` - * @param values The groups to add. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("plusAssignAllGroups") - @Suppress("NOTHING_TO_INLINE") - public inline operator fun com.google.protobuf.kotlin.DslList.plusAssign(values: kotlin.collections.Iterable) { - addAll(values) - } - /** - * `repeated .patrol.DartTestGroup groups = 3;` - * @param index The index to set the value at. - * @param value The groups to set. - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("setGroups") - public operator fun com.google.protobuf.kotlin.DslList.set(index: kotlin.Int, value: pl.leancode.patrol.contracts.Contracts.DartTestGroup) { - _builder.setGroups(index, value) - } - /** - * `repeated .patrol.DartTestGroup groups = 3;` - */ - @kotlin.jvm.JvmSynthetic - @kotlin.jvm.JvmName("clearGroups") - public fun com.google.protobuf.kotlin.DslList.clear() { - _builder.clearGroups() - } - } -} -public inline fun pl.leancode.patrol.contracts.Contracts.DartTestGroup.copy(block: pl.leancode.patrol.contracts.DartTestGroupKt.Dsl.() -> kotlin.Unit): pl.leancode.patrol.contracts.Contracts.DartTestGroup = - pl.leancode.patrol.contracts.DartTestGroupKt.Dsl._create(this.toBuilder()).apply { block() }._build() - diff --git a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/ListDartTestsResponseKt.kt b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/ListDartTestsResponseKt.kt index b40a14ecc..cc52ba79d 100644 --- a/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/ListDartTestsResponseKt.kt +++ b/packages/patrol/android/src/main/kotlin/pl/leancode/patrol/contracts/ListDartTestsResponseKt.kt @@ -28,9 +28,9 @@ public object ListDartTestsResponseKt { internal fun _build(): pl.leancode.patrol.contracts.Contracts.ListDartTestsResponse = _builder.build() /** - * `.patrol.DartTestGroup group = 1;` + * `.patrol.DartGroupEntry group = 1;` */ - public var group: pl.leancode.patrol.contracts.Contracts.DartTestGroup + public var group: pl.leancode.patrol.contracts.Contracts.DartGroupEntry @JvmName("getGroup") get() = _builder.getGroup() @JvmName("setGroup") @@ -38,13 +38,13 @@ public object ListDartTestsResponseKt { _builder.setGroup(value) } /** - * `.patrol.DartTestGroup group = 1;` + * `.patrol.DartGroupEntry group = 1;` */ public fun clearGroup() { _builder.clearGroup() } /** - * `.patrol.DartTestGroup group = 1;` + * `.patrol.DartGroupEntry group = 1;` * @return Whether the group field is set. */ public fun hasGroup(): kotlin.Boolean { @@ -55,6 +55,6 @@ public object ListDartTestsResponseKt { public inline fun pl.leancode.patrol.contracts.Contracts.ListDartTestsResponse.copy(block: pl.leancode.patrol.contracts.ListDartTestsResponseKt.Dsl.() -> kotlin.Unit): pl.leancode.patrol.contracts.Contracts.ListDartTestsResponse = pl.leancode.patrol.contracts.ListDartTestsResponseKt.Dsl._create(this.toBuilder()).apply { block() }._build() -public val pl.leancode.patrol.contracts.Contracts.ListDartTestsResponseOrBuilder.groupOrNull: pl.leancode.patrol.contracts.Contracts.DartTestGroup? +public val pl.leancode.patrol.contracts.Contracts.ListDartTestsResponseOrBuilder.groupOrNull: pl.leancode.patrol.contracts.Contracts.DartGroupEntry? get() = if (hasGroup()) getGroup() else null diff --git a/packages/patrol/android/src/test/kotlin/pl/leancode/patrol/ContractsExtensionsTest.kt b/packages/patrol/android/src/test/kotlin/pl/leancode/patrol/ContractsExtensionsTest.kt index c8c553380..bd7c491f6 100644 --- a/packages/patrol/android/src/test/kotlin/pl/leancode/patrol/ContractsExtensionsTest.kt +++ b/packages/patrol/android/src/test/kotlin/pl/leancode/patrol/ContractsExtensionsTest.kt @@ -1,37 +1,118 @@ package pl.leancode.patrol import org.junit.Test -import pl.leancode.patrol.contracts.dartTestGroup +import pl.leancode.patrol.contracts.Contracts.DartGroupEntry +import pl.leancode.patrol.contracts.DartGroupEntryKt +import pl.leancode.patrol.contracts.copy +import pl.leancode.patrol.contracts.dartGroupEntry import kotlin.test.assertContentEquals -// TODO: Make sure these tests are run on CI +fun dartTestGroup(block: DartGroupEntryKt.Dsl.() -> Unit): DartGroupEntry { + return dartGroupEntry(block).copy { type = DartGroupEntry.GroupEntryType.GROUP } +} + +fun dartTestCase(block: DartGroupEntryKt.Dsl.() -> Unit): DartGroupEntry { + return dartGroupEntry(block).copy { type = DartGroupEntry.GroupEntryType.TEST } +} class DartTestGroupExtensionsTest { + @Test - fun `listDartFilesFlat() litmus test`() { + fun `listTestsFlat() handles simple hierarchy`() { // given val dartTestGroup = dartTestGroup { - name = "root" - groups += listOf( + name = "" + entries += listOf( dartTestGroup { name = "example_test" + entries += listOf(dartTestCase { name = "increments counter, exits the app, and comes back" }) }, dartTestGroup { - name = "example.example_test" + name = "open_app_test" + entries += listOf(dartTestCase { name = "open maps" }) }, + dartTestGroup { + name = "webview_test" + entries += listOf(dartTestCase { name = "interacts with the LeanCode website in a webview" }) + } ) } // when - val dartTestFiles = dartTestGroup.listFlatDartFiles() + val dartTests = dartTestGroup.listTestsFlat() + + // then + assertContentEquals( + listOf( + dartTestCase { name = "example_test increments counter, exits the app, and comes back" }, + dartTestCase { name = "open_app_test open maps" }, + dartTestCase { name = "webview_test interacts with the LeanCode website in a webview" }, + ), + dartTests, + ) + } + + @Test + fun `listTestsFlat() handles nested hierarchy`() { + // given + val exampleTest = dartTestGroup { + name = "example_test" + entries += listOf( + dartTestCase { name = "the first test" }, + dartTestGroup { + name = "top level group in file" + entries += listOf( + dartTestGroup { + name = "alpha" + entries += listOf( + dartTestCase { name = "first" }, + dartTestCase { name = "second" }, + ) + }, + dartTestCase { name = "test between groups" }, + dartTestGroup { + name = "bravo" + entries += listOf( + dartTestCase { name = "first" }, + dartTestCase { name = "second" }, + ) + }, + ) + } + ) + } + + val openAppTest = dartTestGroup { + name = "open_app_test" + entries += listOf( + dartTestCase { name = "open maps" }, + dartTestCase { name = "open browser" }, + ) + } + + val rootDartTestGroup = dartTestGroup { + name = "" + entries += listOf(exampleTest, openAppTest) + } + + // when + val dartTests = rootDartTestGroup.listTestsFlat() // then assertContentEquals( - dartTestFiles, listOf( - "example_test", - "example.example_test", + // example_test + dartTestCase { name = "example_test the first test" }, + dartTestCase { name = "example_test top level group in file alpha first" }, + dartTestCase { name = "example_test top level group in file alpha second" }, + dartTestCase { name = "example_test top level group in file test between groups" }, + dartTestCase { name = "example_test top level group in file bravo first" }, + dartTestCase { name = "example_test top level group in file bravo second" }, + // open_app_test + dartTestCase { name = "open_app_test open maps" }, + dartTestCase { name = "open_app_test open browser" }, ), + dartTests, ) } } diff --git a/packages/patrol/example/integration_test/internal/README b/packages/patrol/example/integration_test/internal/README new file mode 100644 index 000000000..b708d68e8 --- /dev/null +++ b/packages/patrol/example/integration_test/internal/README @@ -0,0 +1,2 @@ +Tests in this directory are used for developing & testing Patrol itself, not for +demonstrating the API. diff --git a/packages/patrol/example/integration_test/internal/group_test.dart b/packages/patrol/example/integration_test/internal/group_test.dart new file mode 100644 index 000000000..4acbc78ca --- /dev/null +++ b/packages/patrol/example/integration_test/internal/group_test.dart @@ -0,0 +1,45 @@ +import 'package:patrol/src/extensions.dart'; +// ignore: depend_on_referenced_packages +import 'package:test_api/src/backend/invoker.dart'; + +import '../common.dart'; + +void main() { + patrol('at the beginning', ($) async { + await _testBody($); + }); + + group('top level group in file', () { + group('alpha', () { + patrol('first', ($) async { + await _testBody($); + }); + patrol('second', ($) async { + await _testBody($); + }); + }); + + patrol('in the middle', ($) async { + await _testBody($); + }); + + group('bravo', () { + patrol('first', ($) async { + await _testBody($); + }); + patrol('second', ($) async { + await _testBody($); + }); + }); + }); +} + +Future _testBody(PatrolTester $) async { + await createApp($); + + final testName = Invoker.current!.fullCurrentTestName(); + await $(#textField).enterText(testName); + + await $.native.pressHome(); + await $.native.openApp(); +} diff --git a/packages/patrol/example/integration_test/open_app_test.dart b/packages/patrol/example/integration_test/open_app_test.dart index be33a8011..c52a7a13c 100644 --- a/packages/patrol/example/integration_test/open_app_test.dart +++ b/packages/patrol/example/integration_test/open_app_test.dart @@ -5,14 +5,16 @@ import 'package:flutter/material.dart'; import 'common.dart'; void main() { - late String mapsId; - if (Platform.isIOS) { - mapsId = 'com.apple.Maps'; - } else if (Platform.isAndroid) { - mapsId = 'com.google.android.apps.maps'; - } - - patrol('counter state is the same after switching apps', ($) async { + patrol('open maps', ($) async { + final String mapsId; + if (Platform.isIOS) { + mapsId = 'com.apple.Maps'; + } else if (Platform.isAndroid) { + mapsId = 'com.google.android.apps.maps'; + } else { + throw UnsupportedError('Unsupported platform'); + } + await createApp($); expect($(#counterText).text, '0'); @@ -26,4 +28,28 @@ void main() { expect($(#counterText).text, '1'); }); + + patrol('open browser', ($) async { + final String browserId; + if (Platform.isIOS) { + browserId = 'com.apple.mobilesafari'; + } else if (Platform.isAndroid) { + browserId = 'com.android.chrome'; + } else { + throw UnsupportedError('Unsupported platform'); + } + + await createApp($); + + expect($(#counterText).text, '0'); + + await $(FloatingActionButton).tap(); + + await $.native.pressHome(); + await $.native.openApp(appId: browserId); + await $.native.pressHome(); + await $.native.openApp(); + + expect($(#counterText).text, '1'); + }); } diff --git a/packages/patrol/example/integration_test/notifications_test.dart b/packages/patrol/example/integration_test/permissions/notifications_test.dart similarity index 96% rename from packages/patrol/example/integration_test/notifications_test.dart rename to packages/patrol/example/integration_test/permissions/notifications_test.dart index c51ad1099..27758ce71 100644 --- a/packages/patrol/example/integration_test/notifications_test.dart +++ b/packages/patrol/example/integration_test/permissions/notifications_test.dart @@ -1,4 +1,4 @@ -import 'common.dart'; +import '../common.dart'; void main() { patrol( diff --git a/packages/patrol/example/integration_test/permissions_location_test.dart b/packages/patrol/example/integration_test/permissions/permissions_location_test.dart similarity index 98% rename from packages/patrol/example/integration_test/permissions_location_test.dart rename to packages/patrol/example/integration_test/permissions/permissions_location_test.dart index 172df4cb7..cc312b023 100644 --- a/packages/patrol/example/integration_test/permissions_location_test.dart +++ b/packages/patrol/example/integration_test/permissions/permissions_location_test.dart @@ -3,7 +3,7 @@ import 'dart:io' as io; import 'package:permission_handler/permission_handler.dart'; -import 'common.dart'; +import '../common.dart'; const _timeout = Duration(seconds: 5); // to avoid timeouts on CI diff --git a/packages/patrol/example/integration_test/permissions_many_test.dart b/packages/patrol/example/integration_test/permissions/permissions_many_test.dart similarity index 98% rename from packages/patrol/example/integration_test/permissions_many_test.dart rename to packages/patrol/example/integration_test/permissions/permissions_many_test.dart index f1e5941b2..e9d1c97b5 100644 --- a/packages/patrol/example/integration_test/permissions_many_test.dart +++ b/packages/patrol/example/integration_test/permissions/permissions_many_test.dart @@ -1,6 +1,6 @@ import 'package:permission_handler/permission_handler.dart'; -import 'common.dart'; +import '../common.dart'; const _timeout = Duration(seconds: 5); // to avoid timeouts on CI diff --git a/packages/patrol/example/integration_test/swipe_test.dart b/packages/patrol/example/integration_test/swipe_test.dart index ef959d108..370223659 100644 --- a/packages/patrol/example/integration_test/swipe_test.dart +++ b/packages/patrol/example/integration_test/swipe_test.dart @@ -3,11 +3,13 @@ import 'dart:io' show Platform; import 'common.dart'; void main() { - late String appId; + final String appId; if (Platform.isIOS) { appId = 'com.apple.Preferences'; } else if (Platform.isAndroid) { appId = 'com.android.settings'; + } else { + throw UnsupportedError('Unsupported platform'); } patrol('scrolls the Settings app', ($) async { diff --git a/packages/patrol/example/ios/Runner.xcodeproj/project.pbxproj b/packages/patrol/example/ios/Runner.xcodeproj/project.pbxproj index 13a049c99..db11d1e62 100644 --- a/packages/patrol/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/patrol/example/ios/Runner.xcodeproj/project.pbxproj @@ -265,7 +265,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1430; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/packages/patrol/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/patrol/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 327fff847..05552f28c 100644 --- a/packages/patrol/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/patrol/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ =4.2) + +extension Patrol_DartGroupEntry.GroupEntryType: CaseIterable { + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Patrol_DartGroupEntry.GroupEntryType] = [ + .group, + .test, + ] +} + +#endif // swift(>=4.2) + public struct Patrol_RunDartTestRequest { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -139,7 +167,7 @@ public struct Patrol_RunDartTestResponse { extension Patrol_RunDartTestResponse.Result: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. - public static var allCases: [Patrol_RunDartTestResponse.Result] = [ + public static let allCases: [Patrol_RunDartTestResponse.Result] = [ .success, .skipped, .failure, @@ -398,19 +426,7 @@ public struct Patrol_EnterTextRequest { public enum KeyboardBehavior: SwiftProtobuf.Enum { public typealias RawValue = Int - - /// The default keyboard behavior. - /// - /// Keyboard will be shown when entering text starts, and will be - /// automatically dismissed afterwards. case showAndDismiss // = 0 - - /// The alternative keyboard behavior. - /// - /// On Android, no keyboard will be shown at all. The text will simply appear - /// inside the TextField. - /// - /// On iOS, the keyboard will not be dismissed after entering text. case alternative // = 1 case UNRECOGNIZED(Int) @@ -443,7 +459,7 @@ public struct Patrol_EnterTextRequest { extension Patrol_EnterTextRequest.KeyboardBehavior: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. - public static var allCases: [Patrol_EnterTextRequest.KeyboardBehavior] = [ + public static let allCases: [Patrol_EnterTextRequest.KeyboardBehavior] = [ .showAndDismiss, .alternative, ] @@ -543,7 +559,7 @@ public struct Patrol_HandlePermissionRequest { extension Patrol_HandlePermissionRequest.Code: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. - public static var allCases: [Patrol_HandlePermissionRequest.Code] = [ + public static let allCases: [Patrol_HandlePermissionRequest.Code] = [ .whileUsing, .onlyThisTime, .denied, @@ -596,7 +612,7 @@ public struct Patrol_SetLocationAccuracyRequest { extension Patrol_SetLocationAccuracyRequest.LocationAccuracy: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. - public static var allCases: [Patrol_SetLocationAccuracyRequest.LocationAccuracy] = [ + public static let allCases: [Patrol_SetLocationAccuracyRequest.LocationAccuracy] = [ .coarse, .fine, ] @@ -832,8 +848,8 @@ public struct Patrol_SubmitTestResultsRequest { #if swift(>=5.5) && canImport(_Concurrency) extension Patrol_ListDartTestsResponse: @unchecked Sendable {} -extension Patrol_DartTestGroup: @unchecked Sendable {} -extension Patrol_DartTestCase: @unchecked Sendable {} +extension Patrol_DartGroupEntry: @unchecked Sendable {} +extension Patrol_DartGroupEntry.GroupEntryType: @unchecked Sendable {} extension Patrol_RunDartTestRequest: @unchecked Sendable {} extension Patrol_RunDartTestResponse: @unchecked Sendable {} extension Patrol_RunDartTestResponse.Result: @unchecked Sendable {} @@ -906,12 +922,12 @@ extension Patrol_ListDartTestsResponse: SwiftProtobuf.Message, SwiftProtobuf._Me } } -extension Patrol_DartTestGroup: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".DartTestGroup" +extension Patrol_DartGroupEntry: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".DartGroupEntry" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 1: .same(proto: "name"), - 2: .same(proto: "tests"), - 3: .same(proto: "groups"), + 3: .same(proto: "type"), + 4: .same(proto: "entries"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -921,8 +937,8 @@ extension Patrol_DartTestGroup: SwiftProtobuf.Message, SwiftProtobuf._MessageImp // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.tests) }() - case 3: try { try decoder.decodeRepeatedMessageField(value: &self.groups) }() + case 3: try { try decoder.decodeSingularEnumField(value: &self.type) }() + case 4: try { try decoder.decodeRepeatedMessageField(value: &self.entries) }() default: break } } @@ -932,54 +948,29 @@ extension Patrol_DartTestGroup: SwiftProtobuf.Message, SwiftProtobuf._MessageImp if !self.name.isEmpty { try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) } - if !self.tests.isEmpty { - try visitor.visitRepeatedMessageField(value: self.tests, fieldNumber: 2) + if self.type != .group { + try visitor.visitSingularEnumField(value: self.type, fieldNumber: 3) } - if !self.groups.isEmpty { - try visitor.visitRepeatedMessageField(value: self.groups, fieldNumber: 3) + if !self.entries.isEmpty { + try visitor.visitRepeatedMessageField(value: self.entries, fieldNumber: 4) } try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Patrol_DartTestGroup, rhs: Patrol_DartTestGroup) -> Bool { + public static func ==(lhs: Patrol_DartGroupEntry, rhs: Patrol_DartGroupEntry) -> Bool { if lhs.name != rhs.name {return false} - if lhs.tests != rhs.tests {return false} - if lhs.groups != rhs.groups {return false} + if lhs.type != rhs.type {return false} + if lhs.entries != rhs.entries {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } } -extension Patrol_DartTestCase: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = _protobuf_package + ".DartTestCase" +extension Patrol_DartGroupEntry.GroupEntryType: SwiftProtobuf._ProtoNameProviding { public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "name"), + 0: .same(proto: "GROUP"), + 1: .same(proto: "TEST"), ] - - public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.name) }() - default: break - } - } - } - - public func traverse(visitor: inout V) throws { - if !self.name.isEmpty { - try visitor.visitSingularStringField(value: self.name, fieldNumber: 1) - } - try unknownFields.traverse(visitor: &visitor) - } - - public static func ==(lhs: Patrol_DartTestCase, rhs: Patrol_DartTestCase) -> Bool { - if lhs.name != rhs.name {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } } extension Patrol_RunDartTestRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { diff --git a/packages/patrol/ios/Classes/PatrolAppServiceClient.swift b/packages/patrol/ios/Classes/PatrolAppServiceClient.swift index b344b7f79..d70dd9c46 100644 --- a/packages/patrol/ios/Classes/PatrolAppServiceClient.swift +++ b/packages/patrol/ios/Classes/PatrolAppServiceClient.swift @@ -41,7 +41,9 @@ import NIO let request = Patrol_Empty() let response = try await client.listDartTests(request) - return response.group.groups.map { $0.name } + return response.group.listTestsFlat(parentGroupName: "").map { + $0.name + } } @objc public func runDartTest(name: String) async throws -> RunDartTestResponse { @@ -55,3 +57,36 @@ import NIO ) } } + +extension Patrol_DartGroupEntry { + + func listTestsFlat(parentGroupName: String) -> [Patrol_DartGroupEntry] { + var tests = [Patrol_DartGroupEntry]() + + for test in self.entries { + var test = test + + if test.type == Patrol_DartGroupEntry.GroupEntryType.test { + if parentGroupName.isEmpty { + // This case is invalid, because every test will have at least + // 1 named group - its filename. + + fatalError("Invariant violated: test \(test.name) has no named parent group") + } + + test.name = "\(parentGroupName) \(test.name)" + tests.append(test) + } else if test.type == Patrol_DartGroupEntry.GroupEntryType.group { + if parentGroupName.isEmpty { + tests.append(contentsOf: test.listTestsFlat(parentGroupName: test.name)) + } else { + tests.append( + contentsOf: test.listTestsFlat(parentGroupName: "\(parentGroupName) \(test.name)") + ) + } + } + } + + return tests + } +} diff --git a/packages/patrol/ios/Classes/PatrolIntegrationTestRunner.h b/packages/patrol/ios/Classes/PatrolIntegrationTestRunner.h index b5a123da6..d376cedb8 100644 --- a/packages/patrol/ios/Classes/PatrolIntegrationTestRunner.h +++ b/packages/patrol/ios/Classes/PatrolIntegrationTestRunner.h @@ -9,102 +9,102 @@ // For every Flutter dart test, dynamically generate an Objective-C method mirroring the test results // so it is reported as a native XCTest run result. -#define PATROL_INTEGRATION_TEST_IOS_RUNNER(__test_class) \ - @interface __test_class : XCTestCase \ - @end \ - \ - @implementation __test_class \ - \ - +(NSArray *)testInvocations { \ - /* Start native automation gRPC server */ \ - PatrolServer *server = [[PatrolServer alloc] init]; \ - [server startWithCompletionHandler:^(NSError * err) { \ - NSLog(@"Server loop done, error: %@", err); \ - }]; \ - \ - /* Create a client for PatrolAppService, which lets us list and run Dart tests */ \ - __block PatrolAppServiceClient *appServiceClient = [[PatrolAppServiceClient alloc] init]; \ - \ - /* Allow the Local Network permission required by Dart Observatory */ \ - XCUIApplication *springboard = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.springboard"]; \ - XCUIElementQuery *systemAlerts = springboard.alerts; \ - if (systemAlerts.buttons[@"Allow"].exists) { \ - [systemAlerts.buttons[@"Allow"] tap]; \ - } \ - \ - /* Run the app for the first time to gather Dart tests */ \ - [[[XCUIApplication alloc] init] launch]; \ - \ - /* Spin the runloop waiting until the app reports that it is ready to report Dart tests */ \ - while (!server.appReady) { \ - [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; \ - } \ - \ - __block NSArray *dartTestFiles = NULL; \ - [appServiceClient \ - listDartTestsWithCompletionHandler:^(NSArray *_Nullable dartTests, NSError *_Nullable err) { \ - if (err != NULL) { \ - NSLog(@"listDartTests(): failed, err: %@", err); \ - } \ - \ - dartTestFiles = dartTests; \ - }]; \ - \ - /* Spin the runloop waiting until the app reports the Dart tests it contains */ \ - while (!dartTestFiles) { \ - [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; \ - } \ - \ - NSLog(@"Got %lu Dart tests: %@", dartTestFiles.count, dartTestFiles); \ - \ - NSMutableArray *invocations = [[NSMutableArray alloc] init]; \ - \ - /** \ - * Once Dart tests are available, we: \ - * \ - * Step 1. Dynamically add test case methods that request execution of an individual Dart test file. \ - * \ - * Step 2. Create invocations to the generated methods and return them \ - */ \ - \ - for (NSString * dartTestFile in dartTestFiles) { \ - /* Step 1 - dynamically create test cases */ \ - \ - IMP implementation = imp_implementationWithBlock(^(id _self) { \ - [[[XCUIApplication alloc] init] launch]; \ - \ - __block RunDartTestResponse *response = NULL; \ - [appServiceClient runDartTestWithName:dartTestFile \ - completionHandler:^(RunDartTestResponse *_Nullable r, NSError *_Nullable err) { \ - if (err != NULL) { \ - NSLog(@"runDartTestWithName(%@): failed, err: %@", dartTestFile, err); \ - } \ - \ - response = r; \ - }]; \ - \ - /* Wait until Dart test finishes */ \ - while (!response) { \ - [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; \ - } \ - \ - XCTAssertTrue(response.passed, @"%@", response.details); \ - }); \ - NSString *selectorName = [PatrolUtils createMethodNameFromPatrolGeneratedGroup:dartTestFile]; \ - SEL selector = NSSelectorFromString(selectorName); \ - class_addMethod(self, selector, implementation, "v@:"); \ - \ - /* Step 2 – create invocations to the dynamically created methods */ \ - NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector]; \ - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; \ - invocation.selector = selector; \ - \ - NSLog(@"RunnerUITests.testInvocations(): selectorName = %@, signature: %@", selectorName, signature); \ - \ - [invocations addObject:invocation]; \ - } \ - \ - return invocations; \ - } \ - \ +#define PATROL_INTEGRATION_TEST_IOS_RUNNER(__test_class) \ + @interface __test_class : XCTestCase \ + @end \ + \ + @implementation __test_class \ + \ + +(NSArray *)testInvocations { \ + /* Start native automation gRPC server */ \ + PatrolServer *server = [[PatrolServer alloc] init]; \ + [server startWithCompletionHandler:^(NSError * err) { \ + NSLog(@"Server loop done, error: %@", err); \ + }]; \ + \ + /* Create a client for PatrolAppService, which lets us list and run Dart tests */ \ + __block PatrolAppServiceClient *appServiceClient = [[PatrolAppServiceClient alloc] init]; \ + \ + /* Allow the Local Network permission required by Dart Observatory */ \ + XCUIApplication *springboard = [[XCUIApplication alloc] initWithBundleIdentifier:@"com.apple.springboard"]; \ + XCUIElementQuery *systemAlerts = springboard.alerts; \ + if (systemAlerts.buttons[@"Allow"].exists) { \ + [systemAlerts.buttons[@"Allow"] tap]; \ + } \ + \ + /* Run the app for the first time to gather Dart tests */ \ + [[[XCUIApplication alloc] init] launch]; \ + \ + /* Spin the runloop waiting until the app reports that it is ready to report Dart tests */ \ + while (!server.appReady) { \ + [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; \ + } \ + \ + __block NSArray *dartTests = NULL; \ + [appServiceClient \ + listDartTestsWithCompletionHandler:^(NSArray *_Nullable tests, NSError *_Nullable err) { \ + if (err != NULL) { \ + NSLog(@"listDartTests(): failed, err: %@", err); \ + } \ + \ + dartTests = tests; \ + }]; \ + \ + /* Spin the runloop waiting until the app reports the Dart tests it contains */ \ + while (!dartTests) { \ + [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; \ + } \ + \ + NSLog(@"Got %lu Dart tests: %@", dartTests.count, dartTests); \ + \ + NSMutableArray *invocations = [[NSMutableArray alloc] init]; \ + \ + /** \ + * Once Dart tests are available, we: \ + * \ + * Step 1. Dynamically add test case methods that request execution of an individual Dart test file. \ + * \ + * Step 2. Create invocations to the generated methods and return them \ + */ \ + \ + for (NSString * dartTest in dartTests) { \ + /* Step 1 - dynamically create test cases */ \ + \ + IMP implementation = imp_implementationWithBlock(^(id _self) { \ + [[[XCUIApplication alloc] init] launch]; \ + \ + __block RunDartTestResponse *response = NULL; \ + [appServiceClient runDartTestWithName:dartTest \ + completionHandler:^(RunDartTestResponse *_Nullable r, NSError *_Nullable err) { \ + if (err != NULL) { \ + NSLog(@"runDartTestWithName(%@): failed, err: %@", dartTest, err); \ + } \ + \ + response = r; \ + }]; \ + \ + /* Wait until Dart test finishes */ \ + while (!response) { \ + [NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; \ + } \ + \ + XCTAssertTrue(response.passed, @"%@", response.details); \ + }); \ + NSString *selectorName = [PatrolUtils createMethodNameFromPatrolGeneratedGroup:dartTest]; \ + SEL selector = NSSelectorFromString(selectorName); \ + class_addMethod(self, selector, implementation, "v@:"); \ + \ + /* Step 2 – create invocations to the dynamically created methods */ \ + NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector]; \ + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; \ + invocation.selector = selector; \ + \ + NSLog(@"RunnerUITests.testInvocations(): selectorName = %@, signature: %@", selectorName, signature); \ + \ + [invocations addObject:invocation]; \ + } \ + \ + return invocations; \ + } \ + \ @end\ diff --git a/packages/patrol/ios/Classes/PatrolUtils.h b/packages/patrol/ios/Classes/PatrolUtils.h index 76c93ba18..2ae389146 100644 --- a/packages/patrol/ios/Classes/PatrolUtils.h +++ b/packages/patrol/ios/Classes/PatrolUtils.h @@ -6,6 +6,8 @@ NS_ASSUME_NONNULL_BEGIN /// Converts test group names in Dart (generated by Patrol CLI) into a valid Objective-C method name. + (NSString *)createMethodNameFromPatrolGeneratedGroup:(NSString *)dartTestGroup; ++ (NSString *)convertFirstPart:(NSString *)filePath; ++ (NSString *)convertSecondPart:(NSString *)filePath; @end NS_ASSUME_NONNULL_END diff --git a/packages/patrol/ios/Classes/PatrolUtils.m b/packages/patrol/ios/Classes/PatrolUtils.m index 5dc802099..6e778dc36 100644 --- a/packages/patrol/ios/Classes/PatrolUtils.m +++ b/packages/patrol/ios/Classes/PatrolUtils.m @@ -6,10 +6,36 @@ @implementation PatrolUtils + (NSString *)createMethodNameFromPatrolGeneratedGroup:(NSString *)dartGroupName { - NSMutableString *temp = [NSMutableString stringWithString:dartGroupName]; + // Let's assume dartGroupName is "examples.example_test completes main flow". + // It consists of two parts. + // + // The first part, "examples.example_test", reflects the location of the Dart + // test file in the filesystem at integration_test/examples/example_test. + // For the first part of this name to be a valid Objective-C identifier, we convert + // it to "examples_exampleTest" + // + // The second part, "completes main flow" is the name of the test. For it to be a + // valid Objective-C identifier, we convert it to "completesMainFlow". + // + // Then both parts are concatenated together with a "___", resulting in + // "examples_exampleTest___completesMainFlow" + NSArray *parts = [[self class] splitIntoParts:dartGroupName]; + + NSString *firstPart = [[self class] convertFirstPart:parts[0]]; + NSString *secondPart = [[self class] convertSecondPart:parts[1]]; + + NSString *result = @""; + result = [result stringByAppendingString:firstPart]; + result = [result stringByAppendingString:@"___"]; + result = [result stringByAppendingString:secondPart]; + + return result; +} + ++ (NSString *)convertFirstPart:(NSString *)filePath { // Split the string by dot - NSArray *components = [[temp componentsSeparatedByString:@"."] mutableCopy]; + NSArray *components = [[filePath componentsSeparatedByString:@"."] mutableCopy]; // Convert the filename from snake_case to camelCase NSMutableString *fileName = [components.lastObject mutableCopy]; @@ -23,14 +49,52 @@ + (NSString *)createMethodNameFromPatrolGeneratedGroup:(NSString *)dartGroupName [fileName appendString:camelCaseWord]; } - NSMutableArray *pathComponents = - [[components subarrayWithRange:NSMakeRange(0, components.count - 1)] mutableCopy]; + NSRange range = NSMakeRange(0, components.count - 1); + NSMutableArray *pathComponents = [[components subarrayWithRange:range] mutableCopy]; if (pathComponents.count > 0) { NSString *path = [pathComponents componentsJoinedByString:@"_"]; - return [NSString stringWithFormat:@"%@_%@", path, fileName]; - } else { - return fileName; + [fileName setString:[NSString stringWithFormat:@"%@_%@", path, fileName]]; + } + + return fileName; +} + ++ (NSString *)convertSecondPart:(NSString *)testName { + // Convert the filename from "space delimeted words" to camelCasedWords + // NSString.capitalizedString could be used here as well. + + NSArray *words = [testName componentsSeparatedByString:@" "]; + NSMutableString *capitalizedTestName = [words.firstObject mutableCopy]; + [capitalizedTestName setString:words[0]]; + for (NSUInteger i = 1; i < words.count; i++) { + NSString *word = words[i]; + NSString *firstLetter = [[word substringToIndex:1] capitalizedString]; + NSString *restOfWord = [word substringFromIndex:1]; + NSString *camelCaseWord = [firstLetter stringByAppendingString:restOfWord]; + [capitalizedTestName appendString:camelCaseWord]; } + + // Objective-C method names must be alphanumeric. + NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; // invertedSet + [allowedCharacters addCharactersInString:@"_"]; + NSCharacterSet *disallowedCharacters = allowedCharacters.invertedSet; + + // Remove disallowed characters. + NSString *filteredTestName = + [[capitalizedTestName componentsSeparatedByCharactersInSet:disallowedCharacters] componentsJoinedByString:@""]; + return filteredTestName; +} + ++ (NSArray *)splitIntoParts:(NSString *)testName { + // The first space in the original dartGroupName is a good separator for the 2 parts. + NSArray *parts = [[testName componentsSeparatedByString:@" "] mutableCopy]; + NSString *firstPart = parts[0]; + NSString *secondPart = [[parts subarrayWithRange:NSMakeRange(1, parts.count - 1)] componentsJoinedByString:@" "]; + + NSMutableArray *result = [[NSMutableArray alloc] init]; + [result addObject:firstPart]; + [result addObject:secondPart]; + return result; } @end diff --git a/packages/patrol/lib/src/binding.dart b/packages/patrol/lib/src/binding.dart index c8ec6fb30..02a61d8b7 100644 --- a/packages/patrol/lib/src/binding.dart +++ b/packages/patrol/lib/src/binding.dart @@ -8,10 +8,11 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/common.dart'; import 'package:integration_test/integration_test.dart'; import 'package:patrol/patrol.dart'; +import 'package:patrol/src/extensions.dart'; // ignore: implementation_imports, depend_on_referenced_packages import 'package:test_api/src/backend/invoker.dart'; + // ignore: implementation_imports, depend_on_referenced_packages -import 'package:test_api/src/backend/live_test.dart'; import 'constants.dart' as constants; @@ -45,11 +46,10 @@ class PatrolBinding extends IntegrationTestWidgetsFlutterBinding { PatrolBinding() { final oldTestExceptionReporter = reportTestException; reportTestException = (details, testDescription) { - final currentDartTestFile = _currentDartTestFile; - if (currentDartTestFile != null) { + final currentDartTest = _currentDartTest; + if (currentDartTest != null) { assert(!constants.hotRestartEnabled); - _testResults[currentDartTestFile] = - Failure(testDescription, '$details'); + _testResults[currentDartTest] = Failure(testDescription, '$details'); } oldTestExceptionReporter(details, testDescription); }; @@ -60,7 +60,7 @@ class PatrolBinding extends IntegrationTestWidgetsFlutterBinding { return; } - _currentDartTestFile = Invoker.current!.liveTest.parentGroupName; + _currentDartTest = Invoker.current!.fullCurrentTestName(); }); tearDown(() async { @@ -82,18 +82,27 @@ class PatrolBinding extends IntegrationTestWidgetsFlutterBinding { final invoker = Invoker.current!; final nameOfRequestedTest = await patrolAppService.testExecutionRequested; - if (nameOfRequestedTest == _currentDartTestFile) { + + if (nameOfRequestedTest == _currentDartTest) { + logger( + 'finished test $_currentDartTest. Will report its status back to the native side', + ); + final passed = invoker.liveTest.state.result.isPassing; logger( - 'tearDown(): test "$testName" in group "$_currentDartTestFile", passed: $passed', + 'tearDown(): test "$testName" in group "$_currentDartTest", passed: $passed', ); await patrolAppService.markDartTestAsCompleted( - dartFileName: _currentDartTestFile!, + dartFileName: _currentDartTest!, passed: passed, - details: _testResults[_currentDartTestFile!] is Failure - ? (_testResults[_currentDartTestFile!] as Failure?)?.details + details: _testResults[_currentDartTest!] is Failure + ? (_testResults[_currentDartTest!] as Failure?)?.details : null, ); + } else { + logger( + 'finished test $_currentDartTest, but it was not requested, so its status will not be reported back to the native side', + ); } }); } @@ -127,7 +136,7 @@ class PatrolBinding extends IntegrationTestWidgetsFlutterBinding { static PatrolBinding get instance => BindingBase.checkInstance(_instance); static PatrolBinding? _instance; - String? _currentDartTestFile; + String? _currentDartTest; /// Keys are the test descriptions, and values are either [_success] or /// a [Failure]. @@ -164,8 +173,8 @@ class PatrolBinding extends IntegrationTestWidgetsFlutterBinding { @override void attachRootWidget(Widget rootWidget) { assert( - (_currentDartTestFile != null) != (constants.hotRestartEnabled), - '_currentDartTestFile can be null if and only if Hot Restart is enabled', + (_currentDartTest != null) != (constants.hotRestartEnabled), + '_currentDartTest can be null if and only if Hot Restart is enabled', ); const testLabelEnabled = bool.fromEnvironment('PATROL_TEST_LABEL_ENABLED'); @@ -185,7 +194,7 @@ class PatrolBinding extends IntegrationTestWidgetsFlutterBinding { left: 4, ), child: Text( - _currentDartTestFile!, + _currentDartTest!, textDirection: TextDirection.ltr, style: const TextStyle(color: Colors.red), ), @@ -197,10 +206,3 @@ class PatrolBinding extends IntegrationTestWidgetsFlutterBinding { } } } - -extension on LiveTest { - /// Get the direct parent group of the currently running test. - /// - /// The group's name is the name of the Dart test file the test is defined in. - String get parentGroupName => groups.last.name; -} diff --git a/packages/patrol/lib/src/common.dart b/packages/patrol/lib/src/common.dart index 71d101390..34907ab33 100644 --- a/packages/patrol/lib/src/common.dart +++ b/packages/patrol/lib/src/common.dart @@ -7,6 +7,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:meta/meta.dart'; import 'package:patrol/src/binding.dart'; +import 'package:patrol/src/extensions.dart'; import 'package:patrol/src/native/contracts/contracts.pb.dart'; import 'package:patrol/src/native/contracts/contracts.pbgrpc.dart'; import 'package:patrol/src/native/native.dart'; @@ -116,9 +117,10 @@ void patrolTest( // "integration_test/examples" directory, we assume that the name of the // immediate parent group is "examples.example_test". - final parentGroupName = Invoker.current!.liveTest.groups.last.name; + final testName = Invoker.current!.fullCurrentTestName(); + final requestedToExecute = await patrolBinding.patrolAppService - .waitForExecutionRequest(parentGroupName); + .waitForExecutionRequest(testName); if (!requestedToExecute) { return; @@ -161,24 +163,83 @@ void patrolTest( ); } -/// Creates a DartTestGroup by visiting the subgroups of [topLevelGroup]. +/// Creates a DartGroupEntry by visiting the subgroups of [parentGroup]. +/// +/// The initial [parentGroup] is the implicit, unnamed top-level [Group] present +/// in every test case. @internal -DartTestGroup createDartTestGroup( - Group topLevelGroup, { - String prefix = '', +DartGroupEntry createDartTestGroup( + Group parentGroup, { + String name = '', + int level = 0, }) { - final groupName = topLevelGroup.name.replaceFirst(prefix, '').trim(); - final group = DartTestGroup(name: groupName); + final groupDTO = DartGroupEntry( + name: name, + type: DartGroupEntry_GroupEntryType.GROUP, + ); - for (final entry in topLevelGroup.entries) { - if (entry is Group) { - group.groups.add(DartTestGroup(name: entry.name)); + for (final entry in parentGroup.entries) { + // Trim names of current groups + + var name = entry.name; + if (parentGroup.name.isNotEmpty) { + name = deduplicateGroupEntryName(parentGroup.name, entry.name); } - if (entry is Test && entry.name != 'patrol_test_explorer') { - throw StateError('Expected group, got test: ${entry.name}'); + if (entry is Group) { + groupDTO.entries.add( + createDartTestGroup( + entry, + name: name, + level: level + 1, + ), + ); + } else if (entry is Test) { + if (entry.name == 'patrol_test_explorer') { + // throw StateError('Expected group, got test: ${entry.name}'); + // Ignore the bogus test that is used to discover the test structure. + continue; + } + + if (level < 1) { + throw StateError('Test is not allowed to be defined at level $level'); + } + + groupDTO.entries.add( + DartGroupEntry(name: name, type: DartGroupEntry_GroupEntryType.TEST), + ); + } else { + // This should really never happen, because Group and Test are the only + // subclasses of GroupEntry. + throw StateError('invalid state'); } } - return group; + return groupDTO; +} + +/// Allows for retrieving the name of a GroupEntry by stripping the names of all ancestor groups. +@internal +String deduplicateGroupEntryName(String parentName, String currentName) { + return currentName.substring( + parentName.length + 1, + currentName.length, + ); +} + +/// Recursively prints the structure of the test suite. +@internal +void printGroupStructure(DartGroupEntry group, {int indentation = 0}) { + final indent = ' ' * indentation; + debugPrint("$indent-- group: '${group.name}'"); + + for (final entry in group.entries) { + if (entry.type == DartGroupEntry_GroupEntryType.TEST) { + debugPrint("$indent -- test: '${entry.name}'"); + } else { + for (final subgroup in entry.entries) { + printGroupStructure(subgroup, indentation: indentation + 5); + } + } + } } diff --git a/packages/patrol/lib/src/extensions.dart b/packages/patrol/lib/src/extensions.dart new file mode 100644 index 000000000..0f241bec9 --- /dev/null +++ b/packages/patrol/lib/src/extensions.dart @@ -0,0 +1,16 @@ +import 'package:meta/meta.dart'; +// ignore: implementation_imports +import 'package:test_api/src/backend/invoker.dart'; + +/// Provides convenience methods for [Invoker]. +@internal +extension InvokerX on Invoker { + /// Returns the full name of the current test (names of all ancestor groups + + /// name of the current test). + String fullCurrentTestName() { + final parentGroupName = liveTest.groups.last.name; + final testName = liveTest.individualName; + + return '$parentGroupName $testName'; + } +} diff --git a/packages/patrol/lib/src/native/contracts/contracts.pb.dart b/packages/patrol/lib/src/native/contracts/contracts.pb.dart index 46006cdef..e027abda5 100644 --- a/packages/patrol/lib/src/native/contracts/contracts.pb.dart +++ b/packages/patrol/lib/src/native/contracts/contracts.pb.dart @@ -24,17 +24,17 @@ class ListDartTestsResponse extends $pb.GeneratedMessage { ? '' : 'patrol'), createEmptyInstance: create) - ..aOM( + ..aOM( 1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'group', - subBuilder: DartTestGroup.create) + subBuilder: DartGroupEntry.create) ..hasRequiredFields = false; ListDartTestsResponse._() : super(); factory ListDartTestsResponse({ - DartTestGroup? group, + DartGroupEntry? group, }) { final _result = create(); if (group != null) { @@ -72,9 +72,9 @@ class ListDartTestsResponse extends $pb.GeneratedMessage { static ListDartTestsResponse? _defaultInstance; @$pb.TagNumber(1) - DartTestGroup get group => $_getN(0); + DartGroupEntry get group => $_getN(0); @$pb.TagNumber(1) - set group(DartTestGroup v) { + set group(DartGroupEntry v) { setField(1, v); } @@ -83,14 +83,14 @@ class ListDartTestsResponse extends $pb.GeneratedMessage { @$pb.TagNumber(1) void clearGroup() => clearField(1); @$pb.TagNumber(1) - DartTestGroup ensureGroup() => $_ensure(0); + DartGroupEntry ensureGroup() => $_ensure(0); } -class DartTestGroup extends $pb.GeneratedMessage { +class DartGroupEntry extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo( const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' - : 'DartTestGroup', + : 'DartGroupEntry', package: const $pb.PackageName( const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' @@ -101,66 +101,68 @@ class DartTestGroup extends $pb.GeneratedMessage { const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name') - ..pc( - 2, + ..e( + 3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' - : 'tests', - $pb.PbFieldType.PM, - subBuilder: DartTestCase.create) - ..pc( - 3, + : 'type', + $pb.PbFieldType.OE, + defaultOrMaker: DartGroupEntry_GroupEntryType.GROUP, + valueOf: DartGroupEntry_GroupEntryType.valueOf, + enumValues: DartGroupEntry_GroupEntryType.values) + ..pc( + 4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' - : 'groups', + : 'entries', $pb.PbFieldType.PM, - subBuilder: DartTestGroup.create) + subBuilder: DartGroupEntry.create) ..hasRequiredFields = false; - DartTestGroup._() : super(); - factory DartTestGroup({ + DartGroupEntry._() : super(); + factory DartGroupEntry({ $core.String? name, - $core.Iterable? tests, - $core.Iterable? groups, + DartGroupEntry_GroupEntryType? type, + $core.Iterable? entries, }) { final _result = create(); if (name != null) { _result.name = name; } - if (tests != null) { - _result.tests.addAll(tests); + if (type != null) { + _result.type = type; } - if (groups != null) { - _result.groups.addAll(groups); + if (entries != null) { + _result.entries.addAll(entries); } return _result; } - factory DartTestGroup.fromBuffer($core.List<$core.int> i, + factory DartGroupEntry.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory DartTestGroup.fromJson($core.String i, + factory DartGroupEntry.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); @$core.Deprecated('Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') - DartTestGroup clone() => DartTestGroup()..mergeFromMessage(this); + DartGroupEntry clone() => DartGroupEntry()..mergeFromMessage(this); @$core.Deprecated('Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - DartTestGroup copyWith(void Function(DartTestGroup) updates) => - super.copyWith((message) => updates(message as DartTestGroup)) - as DartTestGroup; // ignore: deprecated_member_use + DartGroupEntry copyWith(void Function(DartGroupEntry) updates) => + super.copyWith((message) => updates(message as DartGroupEntry)) + as DartGroupEntry; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static DartTestGroup create() => DartTestGroup._(); - DartTestGroup createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); + static DartGroupEntry create() => DartGroupEntry._(); + DartGroupEntry createEmptyInstance() => create(); + static $pb.PbList createRepeated() => + $pb.PbList(); @$core.pragma('dart2js:noInline') - static DartTestGroup getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static DartTestGroup? _defaultInstance; + static DartGroupEntry getDefault() => _defaultInstance ??= + $pb.GeneratedMessage.$_defaultFor(create); + static DartGroupEntry? _defaultInstance; @$pb.TagNumber(1) $core.String get name => $_getSZ(0); @@ -174,78 +176,20 @@ class DartTestGroup extends $pb.GeneratedMessage { @$pb.TagNumber(1) void clearName() => clearField(1); - @$pb.TagNumber(2) - $core.List get tests => $_getList(1); - @$pb.TagNumber(3) - $core.List get groups => $_getList(2); -} - -class DartTestCase extends $pb.GeneratedMessage { - static final $pb.BuilderInfo _i = $pb.BuilderInfo( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'DartTestCase', - package: const $pb.PackageName( - const $core.bool.fromEnvironment('protobuf.omit_message_names') - ? '' - : 'patrol'), - createEmptyInstance: create) - ..aOS( - 1, - const $core.bool.fromEnvironment('protobuf.omit_field_names') - ? '' - : 'name') - ..hasRequiredFields = false; - - DartTestCase._() : super(); - factory DartTestCase({ - $core.String? name, - }) { - final _result = create(); - if (name != null) { - _result.name = name; - } - return _result; + DartGroupEntry_GroupEntryType get type => $_getN(1); + @$pb.TagNumber(3) + set type(DartGroupEntry_GroupEntryType v) { + setField(3, v); } - factory DartTestCase.fromBuffer($core.List<$core.int> i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromBuffer(i, r); - factory DartTestCase.fromJson($core.String i, - [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => - create()..mergeFromJson(i, r); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - DartTestCase clone() => DartTestCase()..mergeFromMessage(this); - @$core.Deprecated('Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - DartTestCase copyWith(void Function(DartTestCase) updates) => - super.copyWith((message) => updates(message as DartTestCase)) - as DartTestCase; // ignore: deprecated_member_use - $pb.BuilderInfo get info_ => _i; - @$core.pragma('dart2js:noInline') - static DartTestCase create() => DartTestCase._(); - DartTestCase createEmptyInstance() => create(); - static $pb.PbList createRepeated() => - $pb.PbList(); - @$core.pragma('dart2js:noInline') - static DartTestCase getDefault() => _defaultInstance ??= - $pb.GeneratedMessage.$_defaultFor(create); - static DartTestCase? _defaultInstance; - @$pb.TagNumber(1) - $core.String get name => $_getSZ(0); - @$pb.TagNumber(1) - set name($core.String v) { - $_setString(0, v); - } + @$pb.TagNumber(3) + $core.bool hasType() => $_has(1); + @$pb.TagNumber(3) + void clearType() => clearField(3); - @$pb.TagNumber(1) - $core.bool hasName() => $_has(0); - @$pb.TagNumber(1) - void clearName() => clearField(1); + @$pb.TagNumber(4) + $core.List get entries => $_getList(2); } class RunDartTestRequest extends $pb.GeneratedMessage { diff --git a/packages/patrol/lib/src/native/contracts/contracts.pbenum.dart b/packages/patrol/lib/src/native/contracts/contracts.pbenum.dart index 463f042de..322d18dc1 100644 --- a/packages/patrol/lib/src/native/contracts/contracts.pbenum.dart +++ b/packages/patrol/lib/src/native/contracts/contracts.pbenum.dart @@ -9,6 +9,35 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; +class DartGroupEntry_GroupEntryType extends $pb.ProtobufEnum { + static const DartGroupEntry_GroupEntryType GROUP = + DartGroupEntry_GroupEntryType._( + 0, + const $core.bool.fromEnvironment('protobuf.omit_enum_names') + ? '' + : 'GROUP'); + static const DartGroupEntry_GroupEntryType TEST = + DartGroupEntry_GroupEntryType._( + 1, + const $core.bool.fromEnvironment('protobuf.omit_enum_names') + ? '' + : 'TEST'); + + static const $core.List values = + [ + GROUP, + TEST, + ]; + + static final $core.Map<$core.int, DartGroupEntry_GroupEntryType> _byValue = + $pb.ProtobufEnum.initByValue(values); + static DartGroupEntry_GroupEntryType? valueOf($core.int value) => + _byValue[value]; + + const DartGroupEntry_GroupEntryType._($core.int v, $core.String n) + : super(v, n); +} + class RunDartTestResponse_Result extends $pb.ProtobufEnum { static const RunDartTestResponse_Result SUCCESS = RunDartTestResponse_Result._( diff --git a/packages/patrol/lib/src/native/contracts/contracts.pbjson.dart b/packages/patrol/lib/src/native/contracts/contracts.pbjson.dart index f9e2e9434..cd6e12490 100644 --- a/packages/patrol/lib/src/native/contracts/contracts.pbjson.dart +++ b/packages/patrol/lib/src/native/contracts/contracts.pbjson.dart @@ -18,7 +18,7 @@ const ListDartTestsResponse$json = const { '3': 1, '4': 1, '5': 11, - '6': '.patrol.DartTestGroup', + '6': '.patrol.DartGroupEntry', '10': 'group' }, ], @@ -26,45 +26,44 @@ const ListDartTestsResponse$json = const { /// Descriptor for `ListDartTestsResponse`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List listDartTestsResponseDescriptor = $convert.base64Decode( - 'ChVMaXN0RGFydFRlc3RzUmVzcG9uc2USKwoFZ3JvdXAYASABKAsyFS5wYXRyb2wuRGFydFRlc3RHcm91cFIFZ3JvdXA='); -@$core.Deprecated('Use dartTestGroupDescriptor instead') -const DartTestGroup$json = const { - '1': 'DartTestGroup', + 'ChVMaXN0RGFydFRlc3RzUmVzcG9uc2USLAoFZ3JvdXAYASABKAsyFi5wYXRyb2wuRGFydEdyb3VwRW50cnlSBWdyb3Vw'); +@$core.Deprecated('Use dartGroupEntryDescriptor instead') +const DartGroupEntry$json = const { + '1': 'DartGroupEntry', '2': const [ const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, const { - '1': 'tests', - '3': 2, - '4': 3, - '5': 11, - '6': '.patrol.DartTestCase', - '10': 'tests' + '1': 'type', + '3': 3, + '4': 1, + '5': 14, + '6': '.patrol.DartGroupEntry.GroupEntryType', + '10': 'type' }, const { - '1': 'groups', - '3': 3, + '1': 'entries', + '3': 4, '4': 3, '5': 11, - '6': '.patrol.DartTestGroup', - '10': 'groups' + '6': '.patrol.DartGroupEntry', + '10': 'entries' }, ], + '4': const [DartGroupEntry_GroupEntryType$json], }; -/// Descriptor for `DartTestGroup`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List dartTestGroupDescriptor = $convert.base64Decode( - 'Cg1EYXJ0VGVzdEdyb3VwEhIKBG5hbWUYASABKAlSBG5hbWUSKgoFdGVzdHMYAiADKAsyFC5wYXRyb2wuRGFydFRlc3RDYXNlUgV0ZXN0cxItCgZncm91cHMYAyADKAsyFS5wYXRyb2wuRGFydFRlc3RHcm91cFIGZ3JvdXBz'); -@$core.Deprecated('Use dartTestCaseDescriptor instead') -const DartTestCase$json = const { - '1': 'DartTestCase', +@$core.Deprecated('Use dartGroupEntryDescriptor instead') +const DartGroupEntry_GroupEntryType$json = const { + '1': 'GroupEntryType', '2': const [ - const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, + const {'1': 'GROUP', '2': 0}, + const {'1': 'TEST', '2': 1}, ], }; -/// Descriptor for `DartTestCase`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List dartTestCaseDescriptor = - $convert.base64Decode('CgxEYXJ0VGVzdENhc2USEgoEbmFtZRgBIAEoCVIEbmFtZQ=='); +/// Descriptor for `DartGroupEntry`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List dartGroupEntryDescriptor = $convert.base64Decode( + 'Cg5EYXJ0R3JvdXBFbnRyeRISCgRuYW1lGAEgASgJUgRuYW1lEjkKBHR5cGUYAyABKA4yJS5wYXRyb2wuRGFydEdyb3VwRW50cnkuR3JvdXBFbnRyeVR5cGVSBHR5cGUSMAoHZW50cmllcxgEIAMoCzIWLnBhdHJvbC5EYXJ0R3JvdXBFbnRyeVIHZW50cmllcyIlCg5Hcm91cEVudHJ5VHlwZRIJCgVHUk9VUBAAEggKBFRFU1QQAQ=='); @$core.Deprecated('Use runDartTestRequestDescriptor instead') const RunDartTestRequest$json = const { '1': 'RunDartTestRequest', diff --git a/packages/patrol/lib/src/native/patrol_app_service.dart b/packages/patrol/lib/src/native/patrol_app_service.dart index 2e0e7855e..db3f470c2 100644 --- a/packages/patrol/lib/src/native/patrol_app_service.dart +++ b/packages/patrol/lib/src/native/patrol_app_service.dart @@ -1,10 +1,12 @@ // ignore_for_file: avoid_print + // TODO: Use a logger instead of print import 'dart:async'; import 'dart:io' as io; import 'package:grpc/grpc.dart'; +import 'package:patrol/src/common.dart'; import 'package:patrol/src/native/contracts/contracts.pbgrpc.dart'; const _port = 8082; @@ -37,7 +39,7 @@ class PatrolAppService extends PatrolAppServiceBase { /// The ambient test group that wraps all the other groups and tests in the /// bundled Dart test file. - final DartTestGroup topLevelDartTestGroup; + final DartGroupEntry topLevelDartTestGroup; /// A completer that completes with the name of the Dart test file that was /// requested to execute by the native side. @@ -84,30 +86,32 @@ class PatrolAppService extends PatrolAppServiceBase { ); } - /// Returns when the native side requests execution of a Dart test file. + /// Returns when the native side requests execution of a Dart test. If the + /// native side requsted execution of [dartTest], returns true. Otherwise + /// returns false. /// - /// The native side requests execution by RPC-ing [runDartTest] and providing - /// name of a Dart test file. + /// It's used inside of [patrolTest] to halt execution of test body until + /// [runDartTest] is called. /// - /// Returns true if the native side requsted execution of [dartTestFile]. - /// Returns false otherwise. - Future waitForExecutionRequest(String dartTestFile) async { - print('PatrolAppService: registered "$dartTestFile"'); + /// The native side requests execution by RPC-ing [runDartTest] and providing + /// name of a Dart test that it wants to currently execute [dartTest]. + Future waitForExecutionRequest(String dartTest) async { + print('PatrolAppService: registered "$dartTest"'); - final requestedDartTestFile = await testExecutionRequested; - if (requestedDartTestFile != dartTestFile) { - // If the requested Dart test file is not the one we're waiting for now, - // it means that dartTestFile was already executed. Return false so that - // callers can skip the already executed test. + final requestedDartTest = await testExecutionRequested; + if (requestedDartTest != dartTest) { + // If the requested Dart test is not the one we're waiting for now, it + // means that dartTest was already executed. Return false so that callers + // can skip the already executed test. print( - 'PatrolAppService: registered test "$dartTestFile" was not matched by requested test "$requestedDartTestFile"', + 'PatrolAppService: registered test "$dartTest" was not matched by requested test "$requestedDartTest"', ); return false; } - print('PatrolAppService: requested execution of test "$dartTestFile"'); + print('PatrolAppService: requested execution of test "$dartTest"'); return true; } diff --git a/packages/patrol/test/internals_test.dart b/packages/patrol/test/internals_test.dart index 271eb2108..c4d252066 100644 --- a/packages/patrol/test/internals_test.dart +++ b/packages/patrol/test/internals_test.dart @@ -1,25 +1,28 @@ // ignore_for_file: invalid_use_of_internal_member, depend_on_referenced_packages, implementation_imports import 'package:flutter_test/flutter_test.dart'; -import 'package:patrol/src/common.dart' show createDartTestGroup; +import 'package:patrol/src/common.dart' + show createDartTestGroup, deduplicateGroupEntryName; import 'package:patrol/src/native/contracts/contracts.pbgrpc.dart'; import 'package:test_api/src/backend/group.dart'; import 'package:test_api/src/backend/invoker.dart'; import 'package:test_api/src/backend/metadata.dart'; +typedef GroupEntryType = DartGroupEntry_GroupEntryType; + void main() { group('createDartTestGroup()', () { - test('fails if a test is defined', () { + test('fails if a test is defined at top-level', () { // given final topLevelGroup = Group.root([ LocalTest('patrol_test_explorer', Metadata.empty, () {}), LocalTest('some_test', Metadata.empty, () => null), Group('example_test', [ LocalTest('example_test some example test', Metadata.empty, () {}), - ]) + ]), ]); // when - DartTestGroup callback() => createDartTestGroup(topLevelGroup); + DartGroupEntry callback() => createDartTestGroup(topLevelGroup); // then expect( @@ -27,30 +30,28 @@ void main() { throwsA(isA()), ); }); - test('takes only groups into account', () { + + test('smoke test 1', () { // given final topLevelGroup = Group.root([ LocalTest('patrol_test_explorer', Metadata.empty, () {}), Group( - 'permissions.permissions_location_test', + 'example_test', [ - LocalTest( - 'permissions.permissions_location_test accepts location permission', - Metadata.empty, - () {}, - ) + Group('example_test alpha', [ + _localTest('example_test alpha first'), + _localTest('example_test alpha second'), + ]), + Group('example_test bravo', [ + _localTest('example_test bravo first'), + _localTest('example_test bravo second'), + ]), ], ), - Group('permissions.permissions_many_test', [ - LocalTest( - 'permissions.permissions_many_test grants various permissions', - Metadata.empty, - () {}, - ), + Group('open_app_test', [ + _localTest('open_app_test open maps'), + _localTest('open_app_test open browser'), ]), - Group('example_test', [ - LocalTest('example_test some example test', Metadata.empty, () {}), - ]) ]); // when @@ -59,15 +60,131 @@ void main() { // then expect( dartTestGroup, - DartTestGroup( - name: '', - groups: [ - DartTestGroup(name: 'permissions.permissions_location_test'), - DartTestGroup(name: 'permissions.permissions_many_test'), - DartTestGroup(name: 'example_test'), + equals( + DartGroupEntry( + name: '', + type: GroupEntryType.GROUP, + entries: [ + DartGroupEntry( + name: 'example_test', + type: GroupEntryType.GROUP, + entries: [ + DartGroupEntry( + name: 'alpha', + type: GroupEntryType.GROUP, + entries: [ + DartGroupEntry(name: 'first', type: GroupEntryType.TEST), + DartGroupEntry(name: 'second', type: GroupEntryType.TEST), + ], + ), + DartGroupEntry( + name: 'bravo', + type: GroupEntryType.GROUP, + entries: [ + DartGroupEntry(name: 'first', type: GroupEntryType.TEST), + DartGroupEntry(name: 'second', type: GroupEntryType.TEST), + ], + ), + ], + ), + DartGroupEntry( + name: 'open_app_test', + type: GroupEntryType.GROUP, + entries: [ + DartGroupEntry(name: 'open maps', type: GroupEntryType.TEST), + DartGroupEntry( + name: 'open browser', + type: GroupEntryType.TEST, + ), + ], + ), + ], + ), + ), + ); + }); + + test('smoke test 2', () { + // given + final topLevelGroup = Group.root([ + LocalTest('patrol_test_explorer', Metadata.empty, () {}), + Group( + 'example_test', + [ + _localTest('example_test alpha'), + Group('example_test bravo', [ + _localTest('example_test bravo first'), + _localTest('example_test bravo second'), + ]), + _localTest('example_test charlie'), + Group('example_test delta', [ + _localTest('example_test delta first'), + _localTest('example_test delta second'), + ]), + _localTest('example_test echo'), ], ), + ]); + + // when + final dartTestGroup = createDartTestGroup(topLevelGroup); + + // then + expect( + dartTestGroup, + equals( + DartGroupEntry( + name: '', + type: GroupEntryType.GROUP, + entries: [ + DartGroupEntry( + name: 'example_test', + type: GroupEntryType.GROUP, + entries: [ + DartGroupEntry(name: 'alpha', type: GroupEntryType.TEST), + DartGroupEntry( + name: 'bravo', + type: GroupEntryType.GROUP, + entries: [ + DartGroupEntry(name: 'first', type: GroupEntryType.TEST), + DartGroupEntry(name: 'second', type: GroupEntryType.TEST), + ], + ), + DartGroupEntry(name: 'charlie', type: GroupEntryType.TEST), + DartGroupEntry( + name: 'delta', + type: GroupEntryType.GROUP, + entries: [ + DartGroupEntry(name: 'first', type: GroupEntryType.TEST), + DartGroupEntry(name: 'second', type: GroupEntryType.TEST), + ], + ), + DartGroupEntry(name: 'echo', type: GroupEntryType.TEST), + ], + ), + ], + ), + ), + ); + }); + }); + + group('deduplicateGroupEntryName()', () { + test('deduplicates group entry names', () { + // given + const parentEntryName = 'example_test example_test.dart alpha'; + const currentEntryName = 'example_test example_test.dart alpha first'; + + // when + final result = deduplicateGroupEntryName( + parentEntryName, + currentEntryName, ); + + // then + expect(result, equals('first')); }); }); } + +LocalTest _localTest(String name) => LocalTest(name, Metadata.empty, () {}); diff --git a/packages/patrol_cli/lib/src/crossplatform/flutter_tool.dart b/packages/patrol_cli/lib/src/crossplatform/flutter_tool.dart index a963bdcdc..4ca7cda00 100644 --- a/packages/patrol_cli/lib/src/crossplatform/flutter_tool.dart +++ b/packages/patrol_cli/lib/src/crossplatform/flutter_tool.dart @@ -47,7 +47,7 @@ class FlutterTool { target: target, appId: appId, dartDefines: dartDefines, - ) + ), ]); } diff --git a/packages/patrol_cli/lib/src/test_bundler.dart b/packages/patrol_cli/lib/src/test_bundler.dart index c4c45ff17..69e01200d 100644 --- a/packages/patrol_cli/lib/src/test_bundler.dart +++ b/packages/patrol_cli/lib/src/test_bundler.dart @@ -71,7 +71,7 @@ Future main() async { final nativeAutomator = NativeAutomator(config: NativeAutomatorConfig()); await nativeAutomator.initialize(); final binding = PatrolBinding.ensureInitialized(); - final testExplorationCompleter = Completer(); + final testExplorationCompleter = Completer(); // A special test to expore the hierarchy of groups and tests. This is a hack // around https://github.com/dart-lang/test/issues/1998. @@ -79,9 +79,13 @@ Future main() async { // This test must be the first to run. If not, the native side likely won't // receive any tests, and everything will fall apart. test('patrol_test_explorer', () { + // Maybe somewhat counterintuitively, this callback runs *after* the calls + // to group() below. final topLevelGroup = Invoker.current!.liveTest.groups.first; final dartTestGroup = createDartTestGroup(topLevelGroup); testExplorationCompleter.complete(dartTestGroup); + print('patrol_test_explorer: obtained Dart-side test hierarchy:'); + printGroupStructure(dartTestGroup); }); // START: GENERATED TEST GROUPS diff --git a/packages/patrol_cli/test/crossplatform/app_options_test.dart b/packages/patrol_cli/test/crossplatform/app_options_test.dart index 15045ca24..f362fb390 100644 --- a/packages/patrol_cli/test/crossplatform/app_options_test.dart +++ b/packages/patrol_cli/test/crossplatform/app_options_test.dart @@ -76,7 +76,7 @@ void main() { r'.\gradlew.bat', ':app:assembleDevReleaseAndroidTest', r'-Ptarget=C:\Users\john\app\integration_test\app_test.dart', - '-Pdart-defines=RU1BSUw9dXNlckBleGFtcGxlLmNvbQ==,UEFTU1dPUkQ9bnk0bmNhdA==,Zm9vPWJhcg==' + '-Pdart-defines=RU1BSUw9dXNlckBleGFtcGxlLmNvbQ==,UEFTU1dPUkQ9bnk0bmNhdA==,Zm9vPWJhcg==', ]), ); }); @@ -98,7 +98,7 @@ void main() { './gradlew', ':app:assembleDevDebugAndroidTest', '-Ptarget=/Users/john/app/integration_test/app_test.dart', - '-Pdart-defines=RU1BSUw9dXNlckBleGFtcGxlLmNvbQ==,UEFTU1dPUkQ9bnk0bmNhdA==,Zm9vPWJhcg==' + '-Pdart-defines=RU1BSUw9dXNlckBleGFtcGxlLmNvbQ==,UEFTU1dPUkQ9bnk0bmNhdA==,Zm9vPWJhcg==', ]), ); });