package com.googlecode.totallylazy;
import com.googlecode.totallylazy.functions.Curried2;
import com.googlecode.totallylazy.functions.Function1;
import org.junit.Test;
import static com.googlecode.totallylazy.Lense.lense;
import static com.googlecode.totallylazy.numbers.Numbers.increment;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
public class LenseTest {
final Person originalBarry = new Person("Barry", 40, new Address("123 Elm St", new Postcode("E1", "1AB")));
@Test
public void getValueViewedThroughLens() throws Exception {
Lense<Person, Number> personAge = lense(Person.functions.age, Person.functions.setAge);
assertThat(personAge.get(originalBarry).intValue(), is(40));
}
@Test
public void setValueViewedThroughLens() throws Exception {
Lense<Person, Number> personAge = lense(Person.functions.age, Person.functions.setAge);
Person olderBarry = personAge.set(45, originalBarry);
assertThat(olderBarry.age.intValue(), is(45));
}
@Test
public void modifyValueViewThroughLens() throws Exception {
Lense<Person, Number> personAge = lense(Person.functions.age, Person.functions.setAge);
Person oneYearOlderBarry = personAge.modify(originalBarry, increment());
assertThat(oneYearOlderBarry.age.intValue(), is(41));
}
@Test
public void lensCanBeComposed() throws Exception {
Lense<Person, Postcode> personPostcode = Person.lenses.address.then(Address.lenses.postcode);
Person movedBarry = personPostcode.set(new Postcode("SE1", "1AA"), originalBarry);
assertThat(movedBarry.address.postcode.asString(), is("SE1 1AA"));
}
private static class Person {
private final String name;
private final Number age;
private final Address address;
Person(String name, Number age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String toString() {
return name + ": age=" + age + ", address=" + address;
}
public static class lenses {
public static final Lense<Person,Address> address = lense(functions.address, functions.setAddress);
}
public static class functions {
public static final Function1<Person, Number> age = person -> person.age;
public static final Curried2<Number, Person, Person> setAge = (newAge, person) -> new Person(person.name, newAge, person.address);
public static final Function1<Person, Address> address = person -> person.address;
public static final Curried2<Address, Person, Person> setAddress = (newAddress, person) -> new Person(person.name, person.age, newAddress);
}
}
static class Address {
private final String street;
private final Postcode postcode;
Address(String street, Postcode postcode) {
this.street = street;
this.postcode = postcode;
}
public String toString() {
return street + " " + postcode;
}
public static class lenses {
public static final Lense<Address,Postcode> postcode = lense(functions.postcode, functions.setPostcode);
}
public static class functions {
public static final Function1<Address, Postcode> postcode = address -> address.postcode;
public static final Curried2<Postcode, Address, Address> setPostcode = (newPostcode, address) -> new Address(address.street, newPostcode);
}
}
class Postcode {
private final String outward;
private final String inward;
Postcode(String outward, String inward) {
this.outward = outward;
this.inward = inward;
}
public String asString() {
return outward + " " + inward;
}
public String toString() {
return asString();
}
}
}