Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Track obvious input files of the Xcode target build #807

Merged
merged 4 commits into from
Mar 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ void beforeEachCreateProject() throws IOException {
@Test
void executesForDefaultConfigurationByDefault(GradleRunner runner) {
runner.withTasks("DualMacOsIosFramework").build();
assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework/Build/Products/Release-macosx"), anExistingDirectory());
assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFrameworkRelease/Build/Products/Release"), anExistingDirectory());
}

@ParameterizedTest
@ValueSource(strings = {"Debug", "Release"})
void canSelectSdkToUse(String configurationToSelect, GradleRunner runner) {
runner.withTasks("DualMacOsIosFramework").withArgument("-Dconfiguration=" + configurationToSelect).build();

assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework/Build/Products/" + configurationToSelect + "-macosx"), anExistingDirectory());
assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework" + configurationToSelect + "/Build/Products/" + configurationToSelect), anExistingDirectory());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import java.nio.file.Path;

import static dev.gradleplugins.buildscript.blocks.PluginsBlock.plugins;
import static dev.gradleplugins.fixtures.runnerkit.BuildResultMatchers.tasksExecuted;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.MatcherAssert.assertThat;

@EnabledOnOs(OS.MAC)
Expand All @@ -49,6 +49,6 @@ static void setup(GradleRunner runner) throws IOException {

@Test
void doesNotFailTheBuild() {
assertThat(result, tasksExecuted(":Library:GreeterLibRelease", ":CrossProjectReference:GreeterAppRelease", ":CrossProjectReference:GreeterApp"));
assertThat(result.getExecutedTaskPaths(), hasItems(":Library:GreeterLibRelease", ":CrossProjectReference:GreeterAppRelease", ":CrossProjectReference:GreeterApp"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@
import dev.nokee.xcode.objects.buildphase.BuildFileAwareBuilder;
import dev.nokee.xcode.objects.buildphase.PBXBuildFile;
import dev.nokee.xcode.objects.buildphase.PBXBuildPhase;
import dev.nokee.xcode.objects.buildphase.PBXCopyFilesBuildPhase;
import dev.nokee.xcode.objects.buildphase.PBXFrameworksBuildPhase;
import dev.nokee.xcode.objects.buildphase.PBXHeadersBuildPhase;
import dev.nokee.xcode.objects.buildphase.PBXResourcesBuildPhase;
import dev.nokee.xcode.objects.buildphase.PBXShellScriptBuildPhase;
import dev.nokee.xcode.objects.buildphase.PBXSourcesBuildPhase;
import dev.nokee.xcode.objects.files.GroupChild;
import dev.nokee.xcode.objects.files.PBXFileReference;
import dev.nokee.xcode.objects.files.PBXGroup;
import dev.nokee.xcode.objects.files.PBXReference;
import dev.nokee.xcode.objects.targets.BuildPhaseAwareBuilder;
import dev.nokee.xcode.objects.targets.PBXLegacyTarget;
import dev.nokee.xcode.objects.targets.PBXTarget;
Expand All @@ -43,6 +49,7 @@
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
Expand All @@ -53,7 +60,7 @@
import static com.google.common.collect.MoreCollectors.onlyElement;

public final class PBXProjectTestUtils {
public static Consumer<Path> mutateProject(UnaryOperator<PBXProject> action) {
public static Consumer<Path> mutateProject(Function<PBXProject, PBXProject> action) {
return path -> {
assert path.getFileName().toString().endsWith(".xcodeproj");
try (val reader = new PBXProjReader(new AsciiPropertyListReader(Files.newBufferedReader(path.resolve("project.pbxproj"))))) {
Expand All @@ -75,6 +82,10 @@ public static UnaryOperator<PBXProject> mainGroup(BiFunction<? super PBXProject,
return project -> project.toBuilder().mainGroup(action.apply(project, project.getMainGroup())).build();
}

public static UnaryOperator<PBXProject> productsGroup(BiFunction<? super PBXProject, ? super PBXGroup, ? extends PBXGroup> action) {
return mainGroup(children(matching(childNameOrPath("Products"), asGroup(action))));
}

public static <SELF> BiFunction<SELF, PBXGroup, PBXGroup> children(BiFunction<? super SELF, ? super List<GroupChild>, ? extends List<GroupChild>> action) {
return (project, group) -> {
return group.toBuilder().children(action.apply(project, group.getChildren())).build();
Expand All @@ -83,22 +94,21 @@ public static <SELF> BiFunction<SELF, PBXGroup, PBXGroup> children(BiFunction<?

public static <SELF, E> BiFunction<SELF, List<E>, List<E>> matching(Predicate<? super E> predicate, BiFunction<? super SELF, ? super E, ? extends E> action) {
return (self, values) -> {
boolean found = false;
val builder = ImmutableList.<E>builder();
for (E value : values) {
if (predicate.test(value)) {
found = true;
builder.add(action.apply(self, value));
} else {
builder.add(value);
}
}
assert found : "no item matched predicate";
return builder.build();
};
}

public static BiFunction<PBXProject, PBXGroup, PBXGroup> childNamed(String name, BiFunction<? super PBXProject, ? super GroupChild, ? extends GroupChild> action) {
return children(matching(childName(name), action));
}

public static Predicate<GroupChild> childName(String value) {
return it -> it.getName().map(value::equals).orElse(false);
}
Expand All @@ -107,10 +117,22 @@ public static Predicate<GroupChild> childPath(String value) {
return it -> it.getPath().map(value::equals).orElse(false);
}

public static Predicate<GroupChild> nameOrPath(String value) {
public static Predicate<GroupChild> childNameOrPath(String value) {
return childName(value).or(childPath(value));
}

public static Predicate<PBXReference> referenceName(String value) {
return it -> it.getName().map(value::equals).orElse(false);
}

public static Predicate<PBXReference> referencePath(String value) {
return it -> it.getPath().map(value::equals).orElse(false);
}

public static Predicate<PBXReference> referenceNameOrPath(String value) {
return referenceName(value).or(referencePath(value));
}

public static BiFunction<PBXProject, GroupChild, GroupChild> asGroup(BiFunction<? super PBXProject, ? super PBXGroup, ? extends PBXGroup> action) {
return (self, e) -> {
assert e instanceof PBXGroup;
Expand All @@ -132,6 +154,19 @@ public static <SELF, E> BiFunction<SELF, List<E>, List<E>> removeLast() {
return (__, values) -> values.subList(0, values.size() - 1);
}

public static <SELF, E> BiFunction<SELF, List<E>, List<E>> removeIf(Predicate<? super E> predicate) {
return (__, values) -> {
val newValues = new ArrayList<>(values);
boolean found = newValues.removeIf(predicate);
assert found;
return newValues;
};
}

public static <SELF, E> BiFunction<SELF, List<E>, List<E>> clear() {
return (__, values) -> ImmutableList.of();
}

public static <SELF, E> BiFunction<SELF, List<E>, List<E>> add(Function<? super SELF, ? extends E> action) {
return (self, values) -> {
return ImmutableList.<E>builder().addAll(values).add(action.apply(self)).build();
Expand All @@ -146,12 +181,16 @@ public static Function<PBXProject, PBXTargetDependency> targetDependencyTo(Strin

public static Function<PBXProject, PBXBuildFile> buildFileToProduct(String productName) {
return self -> {
val productGroup = (PBXGroup) self.getMainGroup().getChildren().stream().filter(childName("Products")).collect(onlyElement());
val productFile = (PBXFileReference) productGroup.getChildren().stream().filter(nameOrPath(productName)).collect(onlyElement());
val productGroup = (PBXGroup) self.getMainGroup().getChildren().stream().filter(childNameOrPath("Products")).collect(onlyElement());
val productFile = (PBXFileReference) productGroup.getChildren().stream().filter(childNameOrPath(productName)).collect(onlyElement());
return PBXBuildFile.ofFile(productFile);
};
}

public static Function<PBXProject, PBXBuildFile> buildFileToProduct(Function<? super PBXProject, PBXBuildFile.FileReference> action) {
return self -> PBXBuildFile.ofFile(action.apply(self));
}

public static UnaryOperator<PBXProject> targets(BiFunction<? super PBXProject, ? super List<PBXTarget>, ? extends List<PBXTarget>> action) {
return project -> project.toBuilder().targets(action.apply(project, project.getTargets())).build();
}
Expand Down Expand Up @@ -192,11 +231,13 @@ public static BiFunction<PBXProject, PBXTarget, PBXTarget> dependencies(BiFuncti
};
}

public static BiFunction<PBXProject, PBXBuildPhase, PBXBuildPhase> files(BiFunction<? super PBXProject, ? super List<PBXBuildFile>, ? extends List<PBXBuildFile>> action) {
public static <T extends PBXBuildPhase> BiFunction<PBXProject, T, T> files(BiFunction<? super PBXProject, ? super List<PBXBuildFile>, ? extends List<PBXBuildFile>> action) {
return (self, buildPhase) -> {
val builder = buildPhase.toBuilder();
((BuildFileAwareBuilder<?>) builder).files(action.apply(self, buildPhase.getFiles()));
return builder.build();
@SuppressWarnings("unchecked")
val result = (T) builder.build();
return result;
};
}

Expand All @@ -211,6 +252,41 @@ public static BiFunction<PBXProject, PBXBuildPhase, PBXShellScriptBuildPhase> as
};
}

public static BiFunction<PBXProject, PBXBuildPhase, PBXCopyFilesBuildPhase> asCopyFiles(BiFunction<? super PBXProject, ? super PBXCopyFilesBuildPhase, ? extends PBXCopyFilesBuildPhase> action) {
return (self, buildPhase) -> {
assert buildPhase instanceof PBXCopyFilesBuildPhase;
return action.apply(self, (PBXCopyFilesBuildPhase) buildPhase);
};
}

public static BiFunction<PBXProject, PBXBuildPhase, PBXFrameworksBuildPhase> asFrameworks(BiFunction<? super PBXProject, ? super PBXFrameworksBuildPhase, ? extends PBXFrameworksBuildPhase> action) {
return (self, buildPhase) -> {
assert buildPhase instanceof PBXFrameworksBuildPhase;
return action.apply(self, (PBXFrameworksBuildPhase) buildPhase);
};
}

public static BiFunction<PBXProject, PBXBuildPhase, PBXHeadersBuildPhase> asHeaders(BiFunction<? super PBXProject, ? super PBXHeadersBuildPhase, ? extends PBXHeadersBuildPhase> action) {
return (self, buildPhase) -> {
assert buildPhase instanceof PBXHeadersBuildPhase;
return action.apply(self, (PBXHeadersBuildPhase) buildPhase);
};
}

public static BiFunction<PBXProject, PBXBuildPhase, PBXResourcesBuildPhase> asResources(BiFunction<? super PBXProject, ? super PBXResourcesBuildPhase, ? extends PBXResourcesBuildPhase> action) {
return (self, buildPhase) -> {
assert buildPhase instanceof PBXResourcesBuildPhase;
return action.apply(self, (PBXResourcesBuildPhase) buildPhase);
};
}

public static BiFunction<PBXProject, PBXBuildPhase, PBXSourcesBuildPhase> asSources(BiFunction<? super PBXProject, ? super PBXSourcesBuildPhase, ? extends PBXSourcesBuildPhase> action) {
return (self, buildPhase) -> {
assert buildPhase instanceof PBXSourcesBuildPhase;
return action.apply(self, (PBXSourcesBuildPhase) buildPhase);
};
}

public static BiFunction<PBXProject, PBXShellScriptBuildPhase, PBXShellScriptBuildPhase> shellPath(String value) {
return (self, buildPhase) -> buildPhase.toBuilder().shellPath(value).build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,11 @@
*/
package dev.nokee.buildadapter.xcode;

import dev.gradleplugins.runnerkit.BuildResult;
import dev.gradleplugins.runnerkit.GradleRunner;
import dev.gradleplugins.runnerkit.TaskOutcome;
import dev.nokee.DualMacosIosFramework;
import dev.nokee.internal.testing.junit.jupiter.ContextualGradleRunnerParameterResolver;
import dev.nokee.platform.xcode.XcodeSwiftApp;
import net.nokeedev.testing.junit.jupiter.io.TestDirectory;
import net.nokeedev.testing.junit.jupiter.io.TestDirectoryExtension;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
Expand All @@ -36,11 +32,8 @@
import java.nio.file.Path;

import static dev.gradleplugins.buildscript.blocks.PluginsBlock.plugins;
import static dev.nokee.internal.testing.FileSystemMatchers.aFile;
import static dev.nokee.internal.testing.FileSystemMatchers.anExistingDirectory;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertTrue;

@EnabledOnOs(OS.MAC)
@ExtendWith({TestDirectoryExtension.class, ContextualGradleRunnerParameterResolver.class})
Expand All @@ -56,14 +49,14 @@ void beforeEachCreateProject() throws IOException {
@Test
void executesForDefaultSdkByDefault(GradleRunner runner) {
runner.withTasks("DualMacOsIosFramework").build();
assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework/Build/Products/Release-macosx"), anExistingDirectory());
assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFrameworkRelease/Build/Products/Release"), anExistingDirectory());
}

@ParameterizedTest
@ValueSource(strings = {"iphoneos", "macosx", "iphonesimulator"})
void canSelectSdkToUse(String sdkToSelect, GradleRunner runner) {
runner.withTasks("DualMacOsIosFramework").withArgument("-Dsdk=" + sdkToSelect).build();

assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFramework/Build/Products/Release-" + sdkToSelect), anExistingDirectory());
assertThat(testDirectory.resolve("build/subprojects/DualMacOsIosFramework-s1qde6bd3k2h/derivedData/DualMacOsIosFrameworkRelease/Build/Products/Release-" + sdkToSelect), anExistingDirectory());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,48 @@
*/
package dev.nokee.buildadapter.xcode.uptodate;

import dev.gradleplugins.runnerkit.GradleRunner;
import dev.nokee.xcode.objects.buildphase.PBXCopyFilesBuildPhase;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;

import java.io.IOException;

import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.add;
import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.buildPhases;
import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.mutateProject;
import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.removeLast;
import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.targetNamed;
import static dev.nokee.buildadapter.xcode.PBXProjectTestUtils.clear;
import static dev.nokee.internal.testing.GradleRunnerMatchers.outOfDate;
import static org.hamcrest.MatcherAssert.assertThat;

@EnabledOnOs(OS.MAC)
class UpToDateCheckDetectsChangeToPBXAggregateTargetFunctionalTests extends UpToDateCheckSpec {
@BeforeEach
void setup() throws IOException {
xcodeproj(targetUnderTest(buildPhases(add(aBuildPhase()))));

ensureUpToDate(executer);
}

@Override
GradleRunner configure(GradleRunner runner) {
return runner.withTasks("AggregateDebug");
protected String targetUnderTestName() {
return "AppAggregate";
}

@Nested
class BuildPhasesField {
@Test
void outOfDateWhenNewBuildPhase() {
mutateProject(targetNamed("Aggregate", buildPhases(add(PBXCopyFilesBuildPhase.builder().destination(it -> it.frameworks("")).build())))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj"));
void outOfDateWhenBuildPhaseAdded() {
xcodeproj(targetUnderTest(buildPhases(add(aBuildPhase()))));

assertThat(executer.build().task(":UpToDateCheck:AggregateDebug"), outOfDate());
assertThat(targetUnderTestExecution(), outOfDate());
}

@Test
void outOfDateWhenRemoveBuildPhase() {
mutateProject(targetNamed("Aggregate", buildPhases(removeLast()))).accept(testDirectory.resolve("UpToDateCheck.xcodeproj"));
void outOfDateWhenBuildPhaseRemoved() {
xcodeproj(targetUnderTest(buildPhases(clear())));

assertThat(executer.build().task(":UpToDateCheck:AggregateDebug"), outOfDate());
assertThat(targetUnderTestExecution(), outOfDate());
}
}
}
Loading