001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.client.assertion; 018 019import org.apache.juneau.rest.client.*; 020 021/** 022 * A fluent assertion class for a named HTTP response header. 023 * 024 * <p> 025 * Obtain instances via {@link ResponseAssertion#header(String)}. 026 * 027 * <h5 class='section'>See Also:</h5><ul> 028 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/NextGenRestClient">Next-Generation REST Client</a> 029 * </ul> 030 * 031 * @since 9.2.1 032 */ 033@SuppressWarnings({ 034 "resource" // Eclipse resource analysis: response is borrowed; caller closes it 035}) 036public final class ResponseHeaderAssertion { 037 038 private final String name; 039 040 private final RestResponse response; 041 private final ResponseAssertion parent; 042 043 ResponseHeaderAssertion(String name, RestResponse response, ResponseAssertion parent) { 044 this.name = name; 045 this.response = response; 046 this.parent = parent; 047 } 048 049 /** 050 * Asserts that this header is present in the response. 051 * 052 * @return This object (for chaining). 053 * @throws AssertionError If the header is absent. 054 */ 055 public ResponseHeaderAssertion isPresent() { 056 if (response.getFirstHeader(name) == null) 057 throw new AssertionError("Expected header '" + name + "' to be present but was absent"); 058 return this; 059 } 060 061 /** 062 * Asserts that this header is absent from the response. 063 * 064 * @return This object (for chaining). 065 * @throws AssertionError If the header is present. 066 */ 067 public ResponseHeaderAssertion isAbsent() { 068 var h = response.getFirstHeader(name); 069 if (h != null) 070 throw new AssertionError("Expected header '" + name + "' to be absent but was present with value: " + h.value()); 071 return this; 072 } 073 074 /** 075 * Asserts that this header's value equals the expected value (case-sensitive). 076 * 077 * @param expected The expected value. Must not be <jk>null</jk>. 078 * @return This object (for chaining). 079 * @throws AssertionError If the value does not match. 080 */ 081 @SuppressWarnings({ 082 "java:S1201" // 'equals(String)' is an intentional fluent-assertion DSL method (asserts header equality), not an override of Object.equals(Object); renaming would break this public API. 083 }) 084 public ResponseHeaderAssertion equals(String expected) { 085 var h = response.getFirstHeader(name); 086 var actual = h != null ? h.value() : null; 087 if (!expected.equals(actual)) 088 throw new AssertionError("Header '" + name + "': expected '" + expected + "' but got '" + actual + "'"); 089 return this; 090 } 091 092 /** 093 * Asserts that this header's value contains the given substring. 094 * 095 * @param substring The substring to look for. Must not be <jk>null</jk>. 096 * @return This object (for chaining). 097 * @throws AssertionError If the value is absent or does not contain the substring. 098 */ 099 public ResponseHeaderAssertion contains(String substring) { 100 var h = response.getFirstHeader(name); 101 var actual = h != null ? h.value() : null; 102 if (actual == null || !actual.contains(substring)) 103 throw new AssertionError("Header '" + name + "' value '" + actual + "' does not contain '" + substring + "'"); 104 return this; 105 } 106 107 /** 108 * Asserts that this header's value starts with the given prefix. 109 * 110 * @param prefix The expected prefix. Must not be <jk>null</jk>. 111 * @return This object (for chaining). 112 * @throws AssertionError If the value is absent or does not start with the prefix. 113 */ 114 public ResponseHeaderAssertion startsWith(String prefix) { 115 var h = response.getFirstHeader(name); 116 var actual = h != null ? h.value() : null; 117 if (actual == null || !actual.startsWith(prefix)) 118 throw new AssertionError("Header '" + name + "' value '" + actual + "' does not start with '" + prefix + "'"); 119 return this; 120 } 121 122 /** 123 * Asserts that this header's integer value equals the expected value. 124 * 125 * @param expected The expected integer value. 126 * @return This object (for chaining). 127 * @throws AssertionError If the value is absent, not a number, or does not match. 128 */ 129 public ResponseHeaderAssertion integerEquals(int expected) { 130 var h = response.getFirstHeader(name); 131 if (h == null) 132 throw new AssertionError("Header '" + name + "' is absent"); 133 int actual; 134 try { 135 actual = Integer.parseInt(h.value().trim()); 136 } catch (NumberFormatException e) { 137 throw new AssertionError("Header '" + name + "' value '" + h.value() + "' is not a valid integer"); 138 } 139 if (actual != expected) 140 throw new AssertionError("Header '" + name + "': expected " + expected + " but got " + actual); 141 return this; 142 } 143 144 /** 145 * Returns the parent {@link ResponseAssertion} to continue assertion chaining. 146 * 147 * @return The parent assertion. Never <jk>null</jk>. 148 */ 149 public ResponseAssertion and() { 150 return parent; 151 } 152}