package org.javersion.object;
import static com.google.common.collect.Sets.newHashSet;
import static java.util.Collections.singleton;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.javersion.core.Version.DEFAULT_BRANCH;
import static org.javersion.object.ObjectVersionManagerTest.ProductStatus.IN_STOCK;
import static org.javersion.object.ObjectVersionManagerTest.ProductStatus.PRE_ORDER;
import static org.javersion.object.ReflectionEquals.reflectionEquals;
import static org.junit.Assert.assertThat;
import java.math.BigDecimal;
import java.util.Set;
import org.javersion.core.Revision;
import org.javersion.core.Version;
import org.javersion.core.VersionNode;
import org.javersion.path.PropertyPath;
import org.joda.time.DateTime;
import org.junit.Test;
import com.google.common.collect.ImmutableSet;
public class ObjectVersionManagerTest {
public enum ProductStatus {
PRE_ORDER,
IN_STOCK
}
@Versionable
public static class Product {
String name;
BigDecimal price;
DateTime statusDate;
ProductStatus status;
}
private final ObjectVersionManager<Product, Void> versionManager = new ObjectVersionManager<Product, Void>(Product.class).init();
@Test
public void Save_Null() {
ObjectVersion<Void> version = versionManager.versionBuilder(null).build();
assertThat(version.changeset.entrySet(), empty());
defaultMergeNoConflicts(null);
}
@Test
public void is_empty() {
assertThat(versionManager.isEmpty(), equalTo(true));
}
@Test
public void get_branches() {
versionManager.versionBuilder(null).build();
assertThat(versionManager.getBranches(), equalTo(set(DEFAULT_BRANCH)));
}
@Test
public void commit_returns_new_VersionNode() {
ObjectVersion<Void> version = versionManager.versionBuilder(null).build(false);
VersionNode<PropertyPath, Object, Void> versionNode = versionManager.commit(version);
assertThat(versionNode, sameInstance(versionManager.getVersionNode(version.revision)));
}
@Test
public void get_heads() {
assertThat(versionManager.getHeads(), nullValue());
ObjectVersion<Void> version = versionManager.versionBuilder(null).build();
assertThat(versionManager.getHeads(), equalTo(set(version.revision)));
}
@Test
public void is_not_empty() {
versionManager.versionBuilder(null).build();
assertThat(versionManager.isEmpty(), equalTo(false));
}
@Test
public void merge_branches_vs_revisions() {
Revision rev1 = new Revision(),
rev2 = new Revision();
Product product = new Product();
product.name = "product 1";
versionManager.versionBuilder(product).revision(rev2).branch("b1").build();
// Concurrent version with earlier revision in another branch
product.name = "product 2";
versionManager.versionBuilder(product).revision(rev1).branch("b2").parents(ImmutableSet.of()).build();
MergeObject<Product, Void> mergeObject = versionManager.mergeBranches("b2", "b1");
product = mergeObject.object;
assertThat(product.name, equalTo("product 2"));
mergeObject = versionManager.mergeRevisions(mergeObject.getMergeHeads());
product = mergeObject.object;
assertThat(product.name, equalTo("product 1"));
}
@Test
public void Save_Empty() {
Product expected = new Product();
ObjectVersion<Void> version = versionManager.versionBuilder(expected).build();
assertThat(version.changeset.size(), equalTo(1));
defaultMergeNoConflicts(expected);
}
private MergeObject<Product, Void> defaultMergeNoConflicts(Product expected) {
MergeObject<Product, Void> mergeObject = versionManager.mergeBranches(DEFAULT_BRANCH);
Product actual = mergeObject.object;
if (expected != null) {
assertThat(actual, not(sameInstance(expected)));
}
assertThat(actual, reflectionEquals(expected));
assertThat(mergeObject.merge.getConflicts().entries(), empty());
return mergeObject;
}
@Test
public void Linear_Versions() {
Product product = new Product();
product.name = "name";
product.price = new BigDecimal("1.1");
product.status = IN_STOCK;
product.statusDate = new DateTime();
ObjectVersion<Void> version = versionManager.versionBuilder(product).build();
assertThat(version.changeset.size(), equalTo(5));
defaultMergeNoConflicts(product);
product.price = new BigDecimal("2.0");
version = versionManager.versionBuilder(product).build();
assertThat(version.changeset.size(), equalTo(1));
defaultMergeNoConflicts(product);
product.name = "nextgen";
product.status = PRE_ORDER;
product.statusDate = new DateTime();
version = versionManager.versionBuilder(product).build();
assertThat(version.changeset.size(), equalTo(3));
defaultMergeNoConflicts(product);
product.name = null;
version = versionManager.versionBuilder(product).build();
assertThat(version.changeset.size(), equalTo(1));
defaultMergeNoConflicts(product);
}
@Test
public void rebase() {
Revision v1 = new Revision(),
v2 = new Revision();
Product product = new Product();
product.name = "name";
versionManager.versionBuilder(product).revision(v1).build();
product.name = "change";
versionManager.versionBuilder(product).revision(v2).build();
product.name = "rebased conflict";
versionManager.versionBuilder(product)
.parents(v1)
.rebaseOn(singleton(v2))
.build();
MergeObject<Product, Void> merge = versionManager.mergeBranches();
assertThat(merge.getConflicts().isEmpty(), equalTo(true));
assertThat(merge.object.name, equalTo("rebased conflict"));
}
@Test
public void Merge_Price_and_Name() {
// First version
Product product = new Product();
product.name = "name";
product.price = new BigDecimal("1.0");
Revision r1 = versionManager.versionBuilder(product).build().revision;
// Second version, new name
product.name = "name2";
Revision r2 = versionManager.versionBuilder(product).build().revision;
// Concurrent version, new price
product.price = new BigDecimal("2.0");
Revision r3 = versionManager.versionBuilder(product).parents(r1).build().revision;
// Merged
MergeObject<Product, Void> mergeObject = versionManager.mergeBranches(Version.DEFAULT_BRANCH);
assertThat(mergeObject.merge.getMergeHeads(), equalTo(set(r2, r3)));
assertThat(mergeObject.merge.getConflicts().isEmpty(), equalTo(true));
product = mergeObject.object;
assertThat(product.name, equalTo("name2"));
assertThat(product.price, equalTo(new BigDecimal("2.0")));
}
@SafeVarargs
private static <T> Set<T> set(final T... ts) {
return newHashSet(ts);
}
}