001package io.ebean.test; 002 003import io.ebean.DB; 004 005import static org.assertj.core.api.Assertions.assertThat; 006 007/** 008 * Helper for testing to assert that the JSON form of an entity 009 * or list of entities is as expected. 010 * <p> 011 * Using assertContains() we can match the JSON form of an entity 012 * against a subset of JSON content. Typically the subset of JSON 013 * excludes generated properties like id, when created and 014 * when modified properties. 015 * </p> 016 * 017 * <h3>Assert contains</h3> 018 * <pre>{@code 019 * 020 * DbJson.of(order) 021 * .assertContains("/order-partial.json"); 022 * 023 * }</pre> 024 * 025 * 026 * <h3>Assert content matches</h3> 027 * <p> 028 * Using assertContentMatches() we are doing an exact content match. 029 * We typically need to replace generated property values. This assert 030 * will start to fail if the model changes like adding a property to 031 * the entity so we should use it less widely due to the maintenance 032 * burden we have with it. 033 * </p> 034 * 035 * <pre>{@code 036 * 037 * DbJson.of(order) 038 * .replace("id", "whenCreated", "whenModified) 039 * .assertContentMatches("/order-full.json"); 040 * 041 * }</pre> 042 */ 043public class DbJson { 044 045 /** 046 * Create a PrettyJson object that has the JSON form of the entity bean or beans. 047 * 048 * <h3>Assert contains</h3> 049 * <pre>{@code 050 * 051 * DbJson.of(order) 052 * .assertContains("/order-partial.json"); 053 * 054 * }</pre> 055 * 056 * <h3>Assert content matches</h3> 057 * <pre>{@code 058 * 059 * DbJson.of(order) 060 * .replace("id", "whenCreated", "whenModified) 061 * .assertContentMatches("/order-full.json"); 062 * 063 * }</pre> 064 */ 065 public static PrettyJson of(Object bean) { 066 return new PrettyJson(DB.json().toJsonPretty(bean)); 067 } 068 069 /** 070 * Read the content for the given resource path. 071 */ 072 public static String readResource(String resourcePath) { 073 return IOUtils.readResource(resourcePath); 074 } 075 076 /** 077 * Contains the JSON of beans(s). 078 */ 079 public static class PrettyJson { 080 081 private String placeHolder = "\"*\""; 082 private String rawJson; 083 084 PrettyJson(String rawJson) { 085 this.rawJson = rawJson; 086 } 087 088 /** 089 * Set the placeHolder to use when replacing property values. 090 */ 091 public PrettyJson withPlaceholder(String placeHolder) { 092 this.placeHolder = placeHolder; 093 return this; 094 } 095 096 /** 097 * Replace the values of the given properties with a placeholder value. 098 * <p> 099 * Typically we do this on generated properties such as id and timestamp properties. 100 * </p> 101 */ 102 public PrettyJson replace(String... propertyNames) { 103 for (String propertyName : propertyNames) { 104 String placeholder = "\"" + propertyName + "\": " + placeHolder; 105 rawJson = rawJson.replaceAll("\"" + propertyName + "\": (\\d+)", placeholder); 106 rawJson = rawJson.replaceAll("\"" + propertyName + "\": \"(.*?)\"", placeholder); 107 } 108 return this; 109 } 110 111 /** 112 * Return the JSON content. 113 */ 114 public String asJson() { 115 return rawJson; 116 } 117 118 /** 119 * Assert the json exactly matches the content at the given resource path. 120 * 121 * <pre>{@code 122 * 123 * DbJson.of(timedEntries) 124 * .replace("id", "eventTime") 125 * .assertContentMatches("/assertJson/full-1-timed.json"); 126 * 127 * }</pre> 128 */ 129 public void assertContentMatches(String resourcePath) { 130 assertThat(lineEnd(rawJson)).isEqualTo(lineEnd(readResource(resourcePath))); 131 } 132 133 /** 134 * Normalise line ending characters to just use new line. 135 */ 136 private String lineEnd(String content) { 137 return content.replace("\r\n", "\n"); 138 } 139 140 /** 141 * Assert the DB json contains the given json content. 142 * <p> 143 * With this "contains" check the DB Json can contain more content than what 144 * it is checked against. Typically the DB json can contain generated properties 145 * like id values, when created, when modified etc and we leave these out of the 146 * json content we are checking against. 147 * </p> 148 * 149 * @param json The subset json content that should be contained by the DB json. 150 */ 151 public void assertContains(String json) { 152 Json.assertContains(rawJson, json); 153 } 154 155 /** 156 * Assert the DB Json contains the Json at the given resource path. 157 * <p> 158 * With this "contains" check the DB Json can contain more content than what 159 * it is checked against. Typically the DB json can contain generated properties 160 * like id values, when created, when modified etc and we leave these out of the 161 * json content we are checking against. 162 * </p> 163 * 164 * @param resourcePath The resource path of the JSON content we are checking against. 165 */ 166 public void assertContainsResource(String resourcePath) { 167 assertContains(readResource(resourcePath)); 168 } 169 } 170}