@Test
        @FacebookAPIVersion("v2.3")
        public void id_v23() throws Exception {
            facebook.setMockJSON("mock_json/success.json");
            boolean actual = facebook.installTab("137246726435626", "2344061033");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/v2.3/137246726435626/tabs")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("app_id", "2344061033"));

            assertThat(actual, is(true));
        }
    }

    public static class getBlocked extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/page/blocked_2.json");
            ResponseList<User> blocked = facebook.getBlocked();
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/blocked")));

            assertThat(blocked.size(), is(2));
            assertThat(blocked.get(0).getId(), is("1111111111"));
            assertThat(blocked.get(0).getName(), is("Foo Name"));
            assertThat(blocked.get(1).getId(), is("2222222222"));
            assertThat(blocked.get(1).getName(), is("Bar Name"));
        }

        @Test
        public void me_reading() throws Exception {
            facebook.setMockJSON("mock_json/page/blocked.json");
            ResponseList<User> blocked = facebook.getBlocked(new Reading().limit(1));
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/blocked")));
            assertThat(facebook.getEndpointURL(), hasParameter("limit", "1"));

            assertThat(blocked.size(), is(1));
            assertThat(blocked.get(0).getId(), is("1234567890"));
            assertThat(blocked.get(0).getName(), is("Foo Bar"));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/page/blocked_2.json");
            ResponseList<User> blocked = facebook.getBlocked("137246726435626");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/blocked")));

            assertThat(blocked.size(), is(2));
            assertThat(blocked.get(0).getId(), is("1111111111"));
            assertThat(blocked.get(0).getName(), is("Foo Name"));
            assertThat(blocked.get(1).getId(), is("2222222222"));
            assertThat(blocked.get(1).getName(), is("Bar Name"));
        }

        @Test
        public void id_reading() throws Exception {
            facebook.setMockJSON("mock_json/page/blocked.json");
            ResponseList<User> blocked = facebook.getBlocked("137246726435626", new Reading().limit(1));
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/blocked")));
            assertThat(facebook.getEndpointURL(), hasParameter("limit", "1"));

            assertThat(blocked.size(), is(1));
            assertThat(blocked.get(0).getId(), is("1234567890"));
            assertThat(blocked.get(0).getName(), is("Foo Bar"));
        }
    }

    public static class block extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/page/block.json");
            List<String> userIds = new ArrayList<String>();
            String uid1 = "1111111111";
            userIds.add(uid1);
            String uid2 = "2222222222";
            userIds.add(uid2);
            Map<String,Boolean> block = facebook.block(userIds);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/blocked")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("uid", uid1 + "," + uid2));

            assertThat(block.size(), is(2));
            assertThat(block.get(uid1), is(true));
            assertThat(block.get(uid2), is(false));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/page/block.json");
            List<String> userIds = new ArrayList<String>();
            String uid1 = "1111111111";
            userIds.add(uid1);
            String uid2 = "2222222222";
            userIds.add(uid2);
            Map<String,Boolean> block = facebook.block("137246726435626", userIds);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/blocked")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("uid", uid1 + "," + uid2));

            assertThat(block.size(), is(2));
            assertThat(block.get(uid1), is(true));
            assertThat(block.get(uid2), is(false));
        }
    }

    public static class unblock extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            String uid = "1111111111";
            boolean unblock = facebook.unblock(uid);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.DELETE));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/blocked")));
            assertThat(facebook.getEndpointURL(), hasParameter("uid", uid));

            assertThat(unblock, is(true));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            String uid = "1111111111";
            boolean unblock = facebook.unblock("137246726435626", uid);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.DELETE));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/blocked")));
            assertThat(facebook.getEndpointURL(), hasParameter("uid", uid));

            assertThat(unblock, is(true));
        }

        @Test
        @FacebookAPIVersion("v2.3")
        public void id_v23() throws Exception {
            facebook.setMockJSON("mock_json/success.json");
            String uid = "1111111111";
            boolean unblock = facebook.unblock("137246726435626", uid);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.DELETE));
            assertThat(facebook.getEndpointURL(), is(pathOf("/v2.3/137246726435626/blocked")));
            assertThat(facebook.getEndpointURL(), hasParameter("uid", uid));

            assertThat(unblock, is(true));
        }
    }

    public static class getOffers extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/page/offers.json");
            ResponseList<Offer> offers = facebook.getOffers();
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/offers")));

            assertThat(offers.size(), is(1));

            Offer offer = offers.get(0);
            assertThat(offer.getId(), is("11111111"));
            assertThat(offer.getFrom().getId(), is("22222222"));
            assertThat(offer.getFrom().getName(), is("Page Name"));
            assertThat(offer.getFrom().getCategory(), is("Page Category"));
            assertThat(offer.getTitle(), is("The title of the Offer"));
            assertThat(offer.getCreatedTime(), is(iso8601DateOf("2013-06-27T19:00:00+0000")));
            assertThat(offer.getExpirationTime(), is(iso8601DateOf("2014-03-31T12:30:00+0000")));
            assertThat(offer.getTerms(), is("The description of the terms under which the offer can be claimed"));
            assertThat(offer.getImageURL().toString(), is("http://facebook4j.org/image.png"));
            assertThat(offer.getClaimLimit(), is(300));
            assertThat(offer.getCouponType(), is("online_only"));
            assertThat(offer.getRedemptionLink().toString(), is("http://facebook4j.org/redemption"));
            assertThat(offer.getRedemptionCode(), is("998877"));
            assertThat(offer.isPublished(), is(true));
            assertThat(offer.getScheduledPublishTime(), is(1372331021));
            assertThat(offer.getReminderTime(), is(iso8601DateOf("2013-07-27T19:00:00+0000")));
        }

        @Test
        public void me_reading() throws Exception {
            facebook.setMockJSON("mock_json/page/offers.json");
            ResponseList<Offer> offers = facebook.getOffers(new Reading().limit(1));
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/offers")));
            assertThat(facebook.getEndpointURL(), hasParameter("limit", "1"));

            assertThat(offers.size(), is(1));

            Offer offer = offers.get(0);
            assertThat(offer.getId(), is("11111111"));
            assertThat(offer.getFrom().getId(), is("22222222"));
            assertThat(offer.getFrom().getName(), is("Page Name"));
            assertThat(offer.getFrom().getCategory(), is("Page Category"));
            assertThat(offer.getTitle(), is("The title of the Offer"));
            assertThat(offer.getCreatedTime(), is(iso8601DateOf("2013-06-27T19:00:00+0000")));
            assertThat(offer.getExpirationTime(), is(iso8601DateOf("2014-03-31T12:30:00+0000")));
            assertThat(offer.getTerms(), is("The description of the terms under which the offer can be claimed"));
            assertThat(offer.getImageURL().toString(), is("http://facebook4j.org/image.png"));
            assertThat(offer.getClaimLimit(), is(300));
            assertThat(offer.getCouponType(), is("online_only"));
            assertThat(offer.getRedemptionLink().toString(), is("http://facebook4j.org/redemption"));
            assertThat(offer.getRedemptionCode(), is("998877"));
            assertThat(offer.isPublished(), is(true));
            assertThat(offer.getScheduledPublishTime(), is(1372331021));
            assertThat(offer.getReminderTime(), is(iso8601DateOf("2013-07-27T19:00:00+0000")));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/page/offers.json");
            ResponseList<Offer> offers = facebook.getOffers("137246726435626");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/offers")));

            assertThat(offers.size(), is(1));

            Offer offer = offers.get(0);
            assertThat(offer.getId(), is("11111111"));
            assertThat(offer.getFrom().getId(), is("22222222"));
            assertThat(offer.getFrom().getName(), is("Page Name"));
            assertThat(offer.getFrom().getCategory(), is("Page Category"));
            assertThat(offer.getTitle(), is("The title of the Offer"));
            assertThat(offer.getCreatedTime(), is(iso8601DateOf("2013-06-27T19:00:00+0000")));
            assertThat(offer.getExpirationTime(), is(iso8601DateOf("2014-03-31T12:30:00+0000")));
            assertThat(offer.getTerms(), is("The description of the terms under which the offer can be claimed"));
            assertThat(offer.getImageURL().toString(), is("http://facebook4j.org/image.png"));
            assertThat(offer.getClaimLimit(), is(300));
            assertThat(offer.getCouponType(), is("online_only"));
            assertThat(offer.getRedemptionLink().toString(), is("http://facebook4j.org/redemption"));
            assertThat(offer.getRedemptionCode(), is("998877"));
            assertThat(offer.isPublished(), is(true));
            assertThat(offer.getScheduledPublishTime(), is(1372331021));
            assertThat(offer.getReminderTime(), is(iso8601DateOf("2013-07-27T19:00:00+0000")));
        }

        @Test
        public void id_reading() throws Exception {
            facebook.setMockJSON("mock_json/page/offers.json");
            ResponseList<Offer> offers = facebook.getOffers("137246726435626", new Reading().limit(1));
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/offers")));
            assertThat(facebook.getEndpointURL(), hasParameter("limit", "1"));

            assertThat(offers.size(), is(1));

            Offer offer = offers.get(0);
            assertThat(offer.getId(), is("11111111"));
            assertThat(offer.getFrom().getId(), is("22222222"));
            assertThat(offer.getFrom().getName(), is("Page Name"));
            assertThat(offer.getFrom().getCategory(), is("Page Category"));
            assertThat(offer.getTitle(), is("The title of the Offer"));
            assertThat(offer.getCreatedTime(), is(iso8601DateOf("2013-06-27T19:00:00+0000")));
            assertThat(offer.getExpirationTime(), is(iso8601DateOf("2014-03-31T12:30:00+0000")));
            assertThat(offer.getTerms(), is("The description of the terms under which the offer can be claimed"));
            assertThat(offer.getImageURL().toString(), is("http://facebook4j.org/image.png"));
            assertThat(offer.getClaimLimit(), is(300));
            assertThat(offer.getCouponType(), is("online_only"));
            assertThat(offer.getRedemptionLink().toString(), is("http://facebook4j.org/redemption"));
            assertThat(offer.getRedemptionCode(), is("998877"));
            assertThat(offer.isPublished(), is(true));
            assertThat(offer.getScheduledPublishTime(), is(1372331021));
            assertThat(offer.getReminderTime(), is(iso8601DateOf("2013-07-27T19:00:00+0000")));
        }
    }

    public static class getLikedPage extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/page/kitkatit.json");
            Page actual = facebook.getLikedPage("160430023972443");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/likes/160430023972443")));

            assertThat(actual.getId(), is("160430023972443"));
            assertThat(actual.getCategory(), is("Company"));
            assertThat(actual.getName(), is("Kit Kat"));
            assertThat(actual.getCreatedTime(), is(iso8601DateOf("2013-08-29T04:56:49+0000")));
        }

        @Test
        public void me_reading() throws Exception {
            facebook.setMockJSON("mock_json/page/kitkatit_website.json");
            Page actual = facebook.getLikedPage("160430023972443", new Reading().fields("name").fields("website"));
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/likes/160430023972443")));
            assertThat(facebook.getEndpointURL(), hasParameter("fields", "name,website"));

            assertThat(actual.getId(), is("160430023972443"));
            assertThat(actual.getWebsite(), is("www.kitkat.it"));
            assertThat(actual.getName(), is("Kit Kat"));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/page/kitkatit.json");
            Page actual = facebook.getLikedPage("1234567890123456", "160430023972443");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/1234567890123456/likes/160430023972443")));

            assertThat(actual.getId(), is("160430023972443"));
            assertThat(actual.getCategory(), is("Company"));
            assertThat(actual.getName(), is("Kit Kat"));
            assertThat(actual.getCreatedTime(), is(iso8601DateOf("2013-08-29T04:56:49+0000")));
        }

        @Test
        public void id_reading() throws Exception {
            facebook.setMockJSON("mock_json/page/kitkatit_website.json");
            Page actual = facebook.getLikedPage("1234567890123456", "160430023972443", new Reading().fields("name").fields("website"));
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/1234567890123456/likes/160430023972443")));
            assertThat(facebook.getEndpointURL(), hasParameter("fields", "name,website"));

            assertThat(actual.getId(), is("160430023972443"));
            assertThat(actual.getWebsite(), is("www.kitkat.it"));
            assertThat(actual.getName(), is("Kit Kat"));
        }
    }

    public static class createOffer extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/id.json");
            OfferUpdate offerUpdate = new OfferUpdate()
                                      .title("title")
                                      .expirationTime(createCal(2013, 6, 27, 19, 0, 0))
                                      .terms("terms")
                                      .imageURL(new URL("http://facebook4j.org/image_url"))
                                      .claimLimit(300)
                                      .couponType("online_only")
                                      .qrcode("qrcode")
                                      .barcode("barcode")
                                      .redemptionLink(new URL("http://facebook4j.org/redemption_link"))
                                      .redemptionCode("redemption_code")
                                      .isPublished(true)
                                      .scheduledPublishTime(1372331021)
                                      .reminderTime(createCal(2013, 7, 27, 19, 0, 0));
            String offerId = facebook.createOffer(offerUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/offers")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("title", "title"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("expiration_time", "2013-06-27T19:00:00+0000"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("terms", "terms"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("image_url", "http://facebook4j.org/image_url"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("claim_limit", "300"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("coupon_type", "online_only"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("qrcode", "qrcode"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("barcode", "barcode"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("redemption_link", "http://facebook4j.org/redemption_link"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("redemption_code", "redemption_code"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("published", "true"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("scheduled_publish_time", "1372331021"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("reminder_time", "2013-07-27T19:00:00+0000"));

            assertThat(offerId, is("1234567890123456"));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/id.json");
            OfferUpdate offerUpdate = new OfferUpdate()
                                      .title("title")
                                      .expirationTime(createCal(2013, 6, 27, 19, 0, 0))
                                      .terms("terms")
                                      .imageURL(new URL("http://facebook4j.org/image_url"))
                                      .claimLimit(300)
                                      .couponType("online_only")
                                      .qrcode("qrcode")
                                      .barcode("barcode")
                                      .redemptionLink(new URL("http://facebook4j.org/redemption_link"))
                                      .redemptionCode("redemption_code")
                                      .isPublished(true)
                                      .scheduledPublishTime(1372331021)
                                      .reminderTime(createCal(2013, 7, 27, 19, 0, 0));
            String offerId = facebook.createOffer("137246726435626", offerUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/offers")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("title", "title"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("expiration_time", "2013-06-27T19:00:00+0000"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("terms", "terms"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("image_url", "http://facebook4j.org/image_url"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("claim_limit", "300"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("coupon_type", "online_only"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("qrcode", "qrcode"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("barcode", "barcode"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("redemption_link", "http://facebook4j.org/redemption_link"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("redemption_code", "redemption_code"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("published", "true"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("scheduled_publish_time", "1372331021"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("reminder_time", "2013-07-27T19:00:00+0000"));

            assertThat(offerId, is("1234567890123456"));
        }

        @Test
        public void id_media_scheduledPublishTimeAsDate() throws Exception {
            facebook.setMockJSON("mock_json/id.json");
            OfferUpdate offerUpdate = new OfferUpdate()
                                      .title("title")
                                      .expirationTime(createCal(2013, 6, 27, 19, 0, 0))
                                      .terms("terms")
                                      .image(new Media(new File("src/test/resources/test_image.png")))
                                      .claimLimit(300)
                                      .couponType("online_only")
                                      .qrcode("qrcode")
                                      .barcode("barcode")
                                      .redemptionLink(new URL("http://facebook4j.org/redemption_link"))
                                      .redemptionCode("redemption_code")
                                      .isPublished(true)
                                      .scheduledPublishTime(new Date(1372331021000L))
                                      .reminderTime(createCal(2013, 7, 27, 19, 0, 0));
            String offerId = facebook.createOffer("137246726435626", offerUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/offers")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("title", "title"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("expiration_time", "2013-06-27T19:00:00+0000"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("terms", "terms"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("claim_limit", "300"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("coupon_type", "online_only"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("qrcode", "qrcode"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("barcode", "barcode"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("redemption_link", "http://facebook4j.org/redemption_link"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("redemption_code", "redemption_code"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("published", "true"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("scheduled_publish_time", "1372331021"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("reminder_time", "2013-07-27T19:00:00+0000"));

            assertThat(offerId, is("1234567890123456"));
        }
    }

    public static class deleteOffer extends MockFacebookTestBase {
        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            boolean result = facebook.deleteOffer("1234567890123456");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.DELETE));
            assertThat(facebook.getEndpointURL(), is(pathOf("/1234567890123456")));

            assertThat(result, is(true));
        }

        @Test
        @FacebookAPIVersion("v2.3")
        public void id_v23() throws Exception {
            facebook.setMockJSON("mock_json/success.json");
            boolean result = facebook.deleteOffer("1234567890123456");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.DELETE));
            assertThat(facebook.getEndpointURL(), is(pathOf("/v2.3/1234567890123456")));

            assertThat(result, is(true));
        }
    }

    public static class getOffer extends MockFacebookTestBase {
        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/page/offer.json");
            Offer actual = facebook.getOffer("1234567890123456");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.GET));
            assertThat(facebook.getEndpointURL(), is(pathOf("/1234567890123456")));

            assertThat(actual.getRedemptionCode(), is("998877"));
            assertThat(actual.getReminderTime(), is(iso8601DateOf("2013-07-27T19:00:00+0000")));
            assertThat(actual.getClaimLimit(), is(300));
            assertThat(actual.getTerms(), is("The description of the terms under which the offer can be claimed"));
            assertThat(actual.getCouponType(), is("online_only"));
            assertThat(actual.getScheduledPublishTime(), is(1372331021));
            assertThat(actual.getFrom().getId(), is("22222222"));
            assertThat(actual.getFrom().getCategory(), is("Page Category"));
            assertThat(actual.getFrom().getName(), is("Page Name"));
            assertThat(actual.getExpirationTime(), is(iso8601DateOf("2014-03-31T12:30:00+0000")));
            assertThat(actual.getRedemptionLink().toString(), is("http://facebook4j.org/redemption"));
            assertThat(actual.getId(), is("11111111"));
            assertThat(actual.getTitle(), is("The title of the Offer"));
            assertThat(actual.getImageURL().toString(), is("http://facebook4j.org/image.png"));
            assertThat(actual.getCreatedTime(), is(iso8601DateOf("2013-06-27T19:00:00+0000")));
            assertThat(actual.isPublished(), is(true));
        }
    }

    public static class postBackdatingFeed extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/post_id.json");
            BackdatingPostUpdate backdatingPostUpdate = new BackdatingPostUpdate("backdating post test.")
                                                            .backdatedTime(1362249213)
                                                            .backdatedTimeGranularity(BackdatedTimeGranularity.day);
            String actual = facebook.postBackdatingFeed(backdatingPostUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/feed")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("backdated_time", "1362249213"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("backdated_time_granularity", "day"));

            assertThat(actual, is("137246726435626_185932178233747"));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/post_id.json");
            BackdatingPostUpdate backdatingPostUpdate = new BackdatingPostUpdate("backdating post test.")
                                                            .backdatedTime(1362249213)
                                                            .backdatedTimeGranularity(BackdatedTimeGranularity.month);
            String actual = facebook.postBackdatingFeed("137246726435626", backdatingPostUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/feed")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("backdated_time", "1362249213"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("backdated_time_granularity", "month"));

            assertThat(actual, is("137246726435626_185932178233747"));
        }
    }

    public static class postPagePhoto extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/post_id.json");
            Media source = new Media(new File("src/test/resources/test_image.png"));
            PagePhotoUpdate pagePhotoUpdate = new PagePhotoUpdate(source).message("upload photo to the page test.");
            Set<String> countries = new HashSet<String>();
            countries.add("US");
            countries.add("GB");
            TargetingParameter targeting = new TargetingParameter().countries(countries);
            pagePhotoUpdate.setTargeting(targeting);
            FeedTargetingParameter feedTargeting = new FeedTargetingParameter().genders(FeedTargetingParameter.Gender.Male);
            feedTargeting.setAgeMin(20);
            feedTargeting.setAgeMax(40);
            pagePhotoUpdate.setFeedTargeting(feedTargeting);
            String actual = facebook.postPagePhoto(pagePhotoUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/photos")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("message", "upload photo to the page test."));
            assertThat(facebook.getHttpParameters(), hasTargetingParameterWithCountries("US", "GB"));
            assertThat(facebook.getHttpParameters(), hasPostJsonParameter("feed_targeting", "{\"age_min\":20,\"genders\":{\"value\":1},\"age_max\":40}"));

            assertThat(actual, is("137246726435626_185932178233747"));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/post_id.json");
            Media source = new Media(new File("src/test/resources/test_image.png"));
            PagePhotoUpdate pagePhotoUpdate = new PagePhotoUpdate(source).message("upload photo to the page test.");
            Set<String> countries = new HashSet<String>();
            countries.add("US");
            countries.add("GB");
            TargetingParameter targeting = new TargetingParameter().countries(countries);
            pagePhotoUpdate.setTargeting(targeting);
            FeedTargetingParameter feedTargeting = new FeedTargetingParameter().genders(FeedTargetingParameter.Gender.Male);
            feedTargeting.setAgeMin(20);
            feedTargeting.setAgeMax(40);
            pagePhotoUpdate.setFeedTargeting(feedTargeting);
            String actual = facebook.postPagePhoto("137246726435626", pagePhotoUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/photos")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("message", "upload photo to the page test."));
            assertThat(facebook.getHttpParameters(), hasTargetingParameterWithCountries("US", "GB"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("feed_targeting", "{\"age_min\":20,\"genders\":{\"value\":1},\"age_max\":40}"));

            assertThat(actual, is("137246726435626_185932178233747"));
        }

        protected Matcher<HttpParameter[]> hasTargetingParameterWithCountries(String... expectedCountryCodes) {
            final Set<String> expectedCountriesSet = new HashSet<String>(Arrays.asList(expectedCountryCodes));
            return new TypeSafeMatcher<HttpParameter[]>(HttpParameter[].class) {

                private final List<String> actualParams = new ArrayList<String>();

                @Override
                public boolean matchesSafely(HttpParameter[] actual) {
                    for (HttpParameter param : actual) {
                        if (param.getName().equals("targeting")) {
                            actualParams.add(param.getName() + "=" + param.getValue());
                            if (matches(param.getValue())) {
                                return true;
                            }
                        }
                    }
                    return false;
                }

                protected boolean matches(String targetingParamValue) {
                    try {
                        JSONObject targetingParamValueObject = new JSONObject(targetingParamValue);
                        JSONArray actualCountriesArray = targetingParamValueObject.getJSONArray("countries");
                        Set<String> actualCountriesSet = new HashSet<String>();
                        for (int i = 0; i < actualCountriesArray.length(); i++) {
                            String country = actualCountriesArray.getString(i);
                            actualCountriesSet.add(country);
                        }
                        return expectedCountriesSet.equals(actualCountriesSet);
                    } catch (JSONException ignore) {
                        return false;
                    }
                }

                public void describeTo(Description desc) {
                    desc.appendValue("targeting=" + expectedCountriesSet);
                    if (actualParams.size() > 0) {
                        desc.appendText(" but actual is ");
                        desc.appendValue(actualParams.get(0));
                        for (int i = 1; i < actualParams.size(); i++) {
                            desc.appendText(", ");
                            desc.appendValue(actualParams.get(i));
                        }
                    } else {
                        desc.appendText(" but actual has no '" + name + "' parameter");
                    }
                }
            };
        }
    }

    public static class updatePageSetting extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            PageSettingUpdate pageSettingUpdate = new PageSettingUpdate("USERS_CAN_POST", false);
            boolean actual = facebook.updatePageSetting(pageSettingUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/settings")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("setting", "USERS_CAN_POST"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("value", "false"));

            assertThat(actual, is(true));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            PageSettingUpdate pageSettingUpdate = new PageSettingUpdate("USERS_CAN_POST", false);
            boolean actual = facebook.updatePageSetting("137246726435626", pageSettingUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/settings")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("setting", "USERS_CAN_POST"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("value", "false"));

            assertThat(actual, is(true));
        }

        @Test
        @FacebookAPIVersion("v2.3")
        public void id_v23() throws Exception {
            facebook.setMockJSON("mock_json/success.json");
            PageSettingUpdate pageSettingUpdate = new PageSettingUpdate("USERS_CAN_POST", false);
            boolean actual = facebook.updatePageSetting("137246726435626", pageSettingUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/v2.3/137246726435626/settings")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("setting", "USERS_CAN_POST"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("value", "false"));

            assertThat(actual, is(true));
        }
    }

    public static class updatePageCoverPhoto extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            PageCoverUpdate pageCoverUpdate = new PageCoverUpdate("193816910778607").offsetY(20).noFeedStory(true);
            boolean actual = facebook.updatePageCoverPhoto(pageCoverUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("cover", "193816910778607"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("offset_y", "20"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("no_feed_story", "true"));

            assertThat(actual, is(true));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            PageCoverUpdate pageCoverUpdate = new PageCoverUpdate("193816910778607").offsetY(20).noFeedStory(true);
            boolean actual = facebook.updatePageCoverPhoto("137246726435626", pageCoverUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("cover", "193816910778607"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("offset_y", "20"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("no_feed_story", "true"));

            assertThat(actual, is(true));
        }

        @Test
        @FacebookAPIVersion("v2.3")
        public void id_v23() throws Exception {
            facebook.setMockJSON("mock_json/success.json");
            PageCoverUpdate pageCoverUpdate = new PageCoverUpdate("193816910778607").offsetY(20).noFeedStory(true);
            boolean actual = facebook.updatePageCoverPhoto("137246726435626", pageCoverUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/v2.3/137246726435626")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("cover", "193816910778607"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("offset_y", "20"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("no_feed_story", "true"));

            assertThat(actual, is(true));
        }
    }

    public static class displayPagePost extends MockFacebookTestBase {
        @Test
        public void hide() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            boolean actual = facebook.displayPagePost("137246726435626_210759175751047", true);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626_210759175751047")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("is_hidden", "true"));

            assertThat(actual, is(true));
        }

        @Test
        @FacebookAPIVersion("v2.3")
        public void hide_v23() throws Exception {
            facebook.setMockJSON("mock_json/success.json");
            boolean actual = facebook.displayPagePost("137246726435626_210759175751047", true);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/v2.3/137246726435626_210759175751047")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("is_hidden", "true"));

            assertThat(actual, is(true));
        }

        @Test
        public void show() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            boolean actual = facebook.displayPagePost("137246726435626_210759175751047", false);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626_210759175751047")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("is_hidden", "false"));

            assertThat(actual, is(true));
        }

        @Test
        @FacebookAPIVersion("v2.3")
        public void show_v23() throws Exception {
            facebook.setMockJSON("mock_json/success.json");
            boolean actual = facebook.displayPagePost("137246726435626_210759175751047", false);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/v2.3/137246726435626_210759175751047")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("is_hidden", "false"));

            assertThat(actual, is(true));
        }
    }

    public static class updateTab extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            TabUpdate tabUpdate = new TabUpdate()
                                    .position(4)
                                    .nonConnectionLandingTab(true);
            boolean actual = facebook.updateTab("notes", tabUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/tabs/notes")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("position", "4"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("is_non_connection_landing_tab", "true"));

            assertThat(actual, is(true));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            TabUpdate tabUpdate = new TabUpdate()
                                    .position(4)
                                    .nonConnectionLandingTab(true);
            boolean actual = facebook.updateTab("137246726435626", "notes", tabUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/tabs/notes")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("position", "4"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("is_non_connection_landing_tab", "true"));

            assertThat(actual, is(true));
        }

        @Test
        @FacebookAPIVersion("v2.3")
        public void id_v23() throws Exception {
            facebook.setMockJSON("mock_json/success.json");
            TabUpdate tabUpdate = new TabUpdate()
                                    .position(4)
                                    .nonConnectionLandingTab(true);
            boolean actual = facebook.updateTab("137246726435626", "notes", tabUpdate);
            assertThat(facebook.getHttpMethod(), is(RequestMethod.POST));
            assertThat(facebook.getEndpointURL(), is(pathOf("/v2.3/137246726435626/tabs/notes")));
            assertThat(facebook.getHttpParameters(), hasPostParameter("position", "4"));
            assertThat(facebook.getHttpParameters(), hasPostParameter("is_non_connection_landing_tab", "true"));

            assertThat(actual, is(true));
        }
    }

    public static class deleteTab extends MockFacebookTestBase {
        @Test
        public void me() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            boolean actual = facebook.deleteTab("notes");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.DELETE));
            assertThat(facebook.getEndpointURL(), is(pathOf("/me/tabs/notes")));

            assertThat(actual, is(true));
        }

        @Test
        public void id() throws Exception {
            facebook.setMockJSON("mock_json/true.json");
            boolean actual = facebook.deleteTab("137246726435626", "notes");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.DELETE));
            assertThat(facebook.getEndpointURL(), is(pathOf("/137246726435626/tabs/notes")));

            assertThat(actual, is(true));
        }

        @Test
        @FacebookAPIVersion("v2.3")
        public void id_v23() throws Exception {
            facebook.setMockJSON("mock_json/success.json");
            boolean actual = facebook.deleteTab("137246726435626", "notes");
            assertThat(facebook.getHttpMethod(), is(RequestMethod.DELETE));
            assertThat(facebook.getEndpointURL(), is(pathOf("/v2.3/137246726435626/tabs/notes")));

            assertThat(actual, is(true));
        }