├── .gitignore ├── chapter-1 └── sql_room_creation.pdf ├── chapter-9 ├── src │ └── main │ │ ├── resources │ │ └── demo.db │ │ └── java │ │ ├── DataAssistant.java │ │ ├── DataAssistantTools.java │ │ └── QueryTools.java └── pom.xml ├── chapter-11 ├── src │ └── main │ │ ├── java │ │ ├── ActivityRAGDemo.java │ │ └── CompletedRAGDemo.java │ │ └── resources │ │ └── data │ │ ├── get-message-count.txt │ │ ├── delete-room-id.txt │ │ ├── post-logout.txt │ │ ├── post-validate.txt │ │ ├── delete-message-id.txt │ │ ├── get-message-id-read.txt │ │ ├── post-login.txt │ │ ├── get-message.txt │ │ ├── get-report-id.txt │ │ ├── get-report.txt │ │ ├── delete-booking-id.txt │ │ ├── get-message-id.txt │ │ ├── get-room-id.txt │ │ ├── post-message.txt │ │ ├── get-booking-summary.txt │ │ ├── post-room.txt │ │ ├── get-booking.txt │ │ ├── get-room.txt │ │ ├── put-room-id.txt │ │ ├── get-booking-id.txt │ │ ├── post-booking.txt │ │ ├── get-branding.txt │ │ ├── put-booking-id.txt │ │ └── put-branding.txt └── pom.xml ├── chapter-7 ├── prompts │ └── contact-us-form-prompt.txt ├── src │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ ├── pageobjects │ │ ├── MessagePage.java │ │ ├── LoginPage.java │ │ └── ContactFormPage.java │ │ ├── requests │ │ ├── MessageRequest.java │ │ └── MessagePayload.java │ │ └── tests │ │ └── InitialMessageTest.java └── pom.xml ├── chapter-6 └── gpt-api-project │ ├── .gitignore │ ├── src │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ ├── datamanager │ │ └── ContactFormDetails.java │ │ ├── pageobjects │ │ └── ContactFormPage.java │ │ └── checks │ │ └── ExampleTests.java │ └── pom.xml ├── chapter-12 ├── src │ └── main │ │ └── java │ │ ├── JsonlEntry.java │ │ ├── Parser.java │ │ ├── JsonlExporter.java │ │ └── JavaParser.java └── pom.xml ├── chapter-4 ├── pom.xml └── src │ ├── test │ └── java │ │ └── com │ │ └── example │ │ └── TimesheetTest.java │ └── main │ └── java │ └── com │ └── example │ └── Timesheet.java ├── chapter-5 ├── src │ └── test │ │ └── java │ │ └── com │ │ └── example │ │ ├── pageobjects │ │ ├── MessagePage.java │ │ ├── LoginFormPage.java │ │ └── ContactFormPage.java │ │ ├── requests │ │ ├── MessagePayload.java │ │ └── MessageRequest.java │ │ └── tests │ │ └── InitialMessageTest.java ├── pom.xml └── prompts │ └── contact-us-form-prompt.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | **/.idea 2 | **/target 3 | .DS_Store 4 | **/**/.DS_Store 5 | **/**/*.log 6 | -------------------------------------------------------------------------------- /chapter-1/sql_room_creation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwinteringham/generative-ai-and-testing/HEAD/chapter-1/sql_room_creation.pdf -------------------------------------------------------------------------------- /chapter-9/src/main/resources/demo.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwinteringham/generative-ai-and-testing/HEAD/chapter-9/src/main/resources/demo.db -------------------------------------------------------------------------------- /chapter-11/src/main/java/ActivityRAGDemo.java: -------------------------------------------------------------------------------- 1 | public class ActivityRAGDemo { 2 | 3 | public static void main(String[] args) throws Exception { 4 | 5 | } 6 | 7 | } 8 | -------------------------------------------------------------------------------- /chapter-7/prompts/contact-us-form-prompt.txt: -------------------------------------------------------------------------------- 1 | You are an expert Java Developer. Convert the HTML delimited by three hashes into a Java selenium page object using the PageFactory library and @FindBy annotations. 2 | 3 | ### 4 | 5 | ### 6 | -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-message-count.txt: -------------------------------------------------------------------------------- 1 | As a user 2 | In order to get the count of messages 3 | I want to be able to send a GET request to /count endpoint 4 | 5 | Acceptance Criteria 6 | * If successful, the response should contain the count of messages 7 | * If unsuccessful due to bad request, the response should be "Bad Request" 8 | 9 | HTTP Payload contract 10 | { 11 | "count": integer 12 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/delete-room-id.txt: -------------------------------------------------------------------------------- 1 | As a hotel manager 2 | In order to remove a room from inventory 3 | I want to be able to delete a room by its ID 4 | 5 | Acceptance Criteria: 6 | * I should be able to successfully delete a room by providing a valid room ID 7 | * If I provide an invalid room ID, I should receive a 400 Bad Request error 8 | * Upon successful deletion, I should receive a confirmation message 9 | -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/post-logout.txt: -------------------------------------------------------------------------------- 1 | As a logged-in user 2 | In order to end my session 3 | I want to be able to send a logout request 4 | 5 | Acceptance Criteria 6 | * The request must contain a token in the request body 7 | * Upon successful logout, a status code of 200 OK should be returned 8 | * The response body should contain a confirmation message 9 | 10 | HTTP Payload contract 11 | { 12 | "token": "string" 13 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/post-validate.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to validate my authentication token 3 | I want to be able to send a token validation request 4 | 5 | Acceptance Criteria 6 | * The request must contain a token in the request body 7 | * Upon successful validation, a status code of 200 OK should be returned 8 | * The response body should contain a token 9 | 10 | HTTP Payload contract 11 | { 12 | "token": "string" 13 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/delete-message-id.txt: -------------------------------------------------------------------------------- 1 | As a user 2 | In order to delete a specific message 3 | I want to be able to send a DELETE request to /{id} endpoint 4 | 5 | Acceptance Criteria 6 | * The request should contain the message ID in the path 7 | * The request can optionally include a token in the cookie 8 | * If successful, the response should be "OK" 9 | * If unsuccessful due to bad request, the response should be "Bad Request" 10 | -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-message-id-read.txt: -------------------------------------------------------------------------------- 1 | As a user 2 | In order to mark a message as read 3 | I want to be able to send a PUT request to /{id}/read endpoint 4 | 5 | Acceptance Criteria 6 | * The request should contain the message ID in the path 7 | * The request can optionally include a token in the cookie 8 | * If successful, the response should be "OK" 9 | * If unsuccessful due to bad request, the response should be "Bad Request" 10 | -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/post-login.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to access my account 3 | I want to be able to send a login request 4 | 5 | Acceptance Criteria 6 | * The request must contain a username and password in the request body 7 | * Upon successful login, a status code of 200 OK should be returned 8 | * The response body should contain a token 9 | 10 | HTTP Payload contract 11 | { 12 | "username": "string", 13 | "password": "string" 14 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-message.txt: -------------------------------------------------------------------------------- 1 | As a user 2 | In order to retrieve messages 3 | I want to be able to send a GET request to / endpoint 4 | 5 | Acceptance Criteria 6 | * If successful, the response should contain the retrieved messages 7 | * If unsuccessful due to bad request, the response should be "Bad Request" 8 | 9 | HTTP Payload contract 10 | { 11 | "messages": [ 12 | { 13 | "id": 0, 14 | "name": "string", 15 | "subject": "string", 16 | "read": true 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-report-id.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to view a specific room report 3 | I want to be able to send a GET request with the room ID 4 | 5 | Acceptance criteria 6 | * The GET request should include the room ID as a parameter in the path 7 | * Upon successful request, the server should respond with a specific room report 8 | 9 | HTTP Payload contract 10 | { 11 | "report": [ 12 | { 13 | "start": "string", 14 | "end": "string", 15 | "title": "string" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-report.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to view all room reports 3 | I want to be able to send a GET request to the base URL 4 | 5 | Acceptance criteria 6 | * The GET request should not require any parameters other than a valid authentication token in the cookie 7 | * Upon successful request, the server should respond with all room reports 8 | 9 | HTTP Payload contract 10 | { 11 | "report": [ 12 | { 13 | "start": "string", 14 | "end": "string", 15 | "title": "string" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/delete-booking-id.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to cancel my booking 3 | I want to be able to send a DELETE request with the booking ID 4 | 5 | Acceptance Criteria: 6 | - The endpoint should accept a booking ID as a parameter in the path 7 | - If a valid booking ID is provided, the server should cancel the booking and respond with a status of "OK" (200) 8 | - If the booking ID is invalid or missing, the server should respond with a "Bad Request" error (400) 9 | - Optionally, a token can be provided in the cookie for authentication -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-message-id.txt: -------------------------------------------------------------------------------- 1 | As a user 2 | In order to retrieve a specific message 3 | I want to be able to send a GET request to /{id} endpoint 4 | 5 | Acceptance Criteria 6 | * The request should contain the message ID in the path 7 | * If successful, the response should contain the retrieved message 8 | * If unsuccessful due to bad request, the response should be "Bad Request" 9 | 10 | HTTP Payload contract 11 | { 12 | "messageid": Integer, 13 | "name": "String", 14 | "email": "String", 15 | "phone": "String", 16 | "subject": "String", 17 | "description": "String" 18 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-room-id.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to view room details 3 | I want to be able to retrieve information about a specific room by its ID 4 | 5 | Acceptance Criteria: 6 | * I should receive a response containing room details when providing a valid room ID 7 | * If I provide an invalid room ID, I should receive a 400 Bad Request error 8 | 9 | HTTP Payload contract 10 | { 11 | "roomid": integer, 12 | "roomName": "string", 13 | "type": "string", 14 | "accessible": boolean, 15 | "image": "string", 16 | "description": "string", 17 | "features": [ 18 | "string", 19 | ], 20 | "roomPrice": integer 21 | } 22 | -------------------------------------------------------------------------------- /chapter-6/gpt-api-project/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/post-message.txt: -------------------------------------------------------------------------------- 1 | As a user 2 | In order to create a new message 3 | I want to be able to send a POST request to / endpoint 4 | 5 | Acceptance Criteria 6 | * The request should contain a JSON payload representing the message 7 | * The message JSON payload should contain required fields: description, email, name, phone, subject 8 | * If successful, the response should contain the created message 9 | * If unsuccessful due to bad request, the response should be "Bad Request" 10 | 11 | HTTP Payload contract 12 | { 13 | "messageid": integer, 14 | "name": "string", 15 | "email": "string", 16 | "phone": "string", 17 | "subject": "string", 18 | "description": "string" 19 | } -------------------------------------------------------------------------------- /chapter-12/src/main/java/JsonlEntry.java: -------------------------------------------------------------------------------- 1 | public class JsonlEntry { 2 | 3 | private String instruction; 4 | 5 | private String output; 6 | 7 | public JsonlEntry(String instruction, String output) { 8 | this.instruction = instruction; 9 | this.output = output; 10 | } 11 | 12 | public String getInstruction() { 13 | return instruction; 14 | } 15 | 16 | public String getOutput() { 17 | return output; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "JsonLEntry{" + 23 | "instruction='" + instruction + '\'' + 24 | ", output='" + output + '\'' + 25 | '}'; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-booking-summary.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to retrieve a summary of bookings for a specific room 3 | I want to be able to send a GET request with the room ID 4 | 5 | Acceptance Criteria: 6 | - The endpoint should accept a room ID as a query parameter 7 | - The server should respond with a summary of bookings for the specified room 8 | - If the room ID is missing or invalid, the server should respond with a "Bad Request" error (400) 9 | - Optionally, a token can be provided in the cookie for authentication 10 | 11 | HTTP Payload contract 12 | { 13 | "bookings": [ 14 | { 15 | "bookingDates": { 16 | "checkin": "String", 17 | "checkout": "String" 18 | } 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/post-room.txt: -------------------------------------------------------------------------------- 1 | As a hotel manager 2 | In order to add a new room to inventory 3 | I want to be able to create a new room 4 | 5 | Acceptance Criteria: 6 | * I should be able to successfully create a new room by providing required data in the request body 7 | * If I provide invalid data, I should receive a 400 Bad Request error 8 | * Upon successful creation, I should receive a response containing the details of the newly created room 9 | 10 | HTTP Payload contract 11 | { 12 | "roomid": integer, 13 | "roomName": "string", 14 | "type": "string", 15 | "accessible": boolean, 16 | "image": "string", 17 | "description": "string", 18 | "features": [ 19 | "string" 20 | ], 21 | "roomPrice": integer 22 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-booking.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to retrieve a list of bookings 3 | I want to be able to send a GET request to get all bookings 4 | 5 | Acceptance Criteria: 6 | - The endpoint should return a list of all bookings 7 | - Optionally, a room ID can be provided as a query parameter to filter the bookings 8 | - Optionally, a token can be provided in the cookie for authentication 9 | 10 | HTTP Payload contract 11 | { 12 | "bookings": [ 13 | { 14 | "bookingid": Integer, 15 | "roomid": Integer, 16 | "firstname": "String", 17 | "lastname": "String", 18 | "depositpaid": Boolean, 19 | "bookingdates": { 20 | "checkin": "String", 21 | "checkout": "String" 22 | } 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /chapter-12/src/main/java/Parser.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | import java.util.List; 3 | 4 | public class Parser { 5 | 6 | // 'yml', 7 | // 'md', 8 | // 'json', 9 | // 'js', 10 | // 'xml', 11 | // 'properties', 12 | // 'txt', 13 | // 'html', 14 | // 'scss', 15 | // 'snap', 16 | // 'sql', 17 | // 'yaml', 18 | // 'cmd', 19 | // 'sh', 20 | // 'conf' 21 | 22 | public static void main(String[] args) throws IOException { 23 | JavaParser parser = new JavaParser("/Users/mark/Desktop/restful-booker-platform-trunk/"); 24 | 25 | List javaCodeSnippets = parser.getCodeSnippets(); 26 | 27 | JsonlExporter.exportToJsonL(javaCodeSnippets, "/Users/mark/Desktop/parser-test/output.jsonl"); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-room.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to browse available rooms 3 | I want to be able to retrieve a list of all available rooms 4 | 5 | Acceptance Criteria: 6 | * I should receive a response containing a list of available rooms 7 | * If there are no available rooms, I should receive an empty list 8 | * If there's an error retrieving the room list, I should receive a 400 Bad Request error 9 | 10 | HTTP Payload Contract 11 | 12 | { 13 | "rooms": [ 14 | { 15 | "roomid": integer, 16 | "roomName": "string", 17 | "type": "Single", 18 | "accessible": true, 19 | "image": "string", 20 | "description": "string", 21 | "features": [ 22 | "string" 23 | ], 24 | "roomPrice": integer 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/put-room-id.txt: -------------------------------------------------------------------------------- 1 | As a hotel manager 2 | In order to update room information 3 | I want to be able to modify the details of a specific room identified by its ID 4 | 5 | Acceptance Criteria: 6 | * I should be able to successfully update room details by providing a valid room ID and required data in the request body 7 | * If I provide invalid data or an invalid room ID, I should receive a 400 Bad Request error 8 | * If the update is successful, I should receive a response containing the updated room details 9 | 10 | HTTP Payload contract 11 | { 12 | "roomid": integer, 13 | "roomName": "string", 14 | "type": "string", 15 | "accessible": boolean, 16 | "image": "string", 17 | "description": "string", 18 | "features": [ 19 | "string" 20 | ], 21 | "roomPrice": integer 22 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-booking-id.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to retrieve information about a booking 3 | I want to be able to send a GET request with the booking ID 4 | 5 | Acceptance Criteria: 6 | - The endpoint should accept a booking ID as a parameter in the path 7 | - If a valid booking ID is provided, the server should respond with the details of the booking 8 | - If the booking ID is invalid or missing, the server should respond with a "Bad Request" error (400) 9 | - Optionally, a token can be provided in the cookie for authentication 10 | 11 | HTTP Payload contract 12 | { 13 | "bookingid": Integer, 14 | "roomid": Integer, 15 | "firstname": "String", 16 | "lastname": "String", 17 | "depositpaid": Boolean, 18 | "bookingdates": { 19 | "checkin": "String", 20 | "checkout": "String" 21 | } 22 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/post-booking.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to make a new booking 3 | I want to be able to send a POST request with the booking details 4 | 5 | Acceptance Criteria: 6 | - The endpoint should accept booking details in the request body in JSON format 7 | - If the booking is successful, the server should respond with the booking details and a status of "OK" (200) 8 | - If the booking request is invalid, the server should respond with a "Bad Request" error (400) 9 | - Optionally, a token can be provided in the cookie for authentication 10 | 11 | HTTP Payload contract 12 | { 13 | "bookingid": integer, 14 | "roomid": integer, 15 | "firstname": "string", 16 | "lastname": "string", 17 | "depositpaid": boolean, 18 | "email": "string", 19 | "phone": "string", 20 | "bookingdates": { 21 | "checkin": "string", 22 | "checkout": "string" 23 | } 24 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/get-branding.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to retrieve branding information 3 | I want to be able to send a GET request to /branding/ 4 | 5 | Acceptance criteria 6 | * Upon sending a GET request to /branding/, I should receive branding information in the response. 7 | * If the request is successful, the response status should be 200 OK. 8 | * If the request is unsuccessful due to bad parameters or missing data, the response status should be 400 Bad Request. 9 | * The response body should conform to the schema defined in the Swagger JSON. 10 | 11 | HTTP Payload contract 12 | { 13 | "name": "string", 14 | "map": { 15 | "latitude": integer, 16 | "longitude": integer 17 | }, 18 | "logoUrl": "string", 19 | "description": "string", 20 | "contact": { 21 | "name": "string", 22 | "address": "string", 23 | "phone": "string", 24 | "email": "string" 25 | } 26 | } -------------------------------------------------------------------------------- /chapter-12/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | parser-test 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 18 13 | 18 14 | UTF-8 15 | 16 | 17 | 18 | 19 | com.github.javaparser 20 | javaparser-core 21 | 3.24.0 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/put-booking-id.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to update my booking information 3 | I want to be able to send a PUT request with the booking ID and updated details 4 | 5 | Acceptance Criteria: 6 | - The endpoint should accept a booking ID as a parameter in the path 7 | - The updated booking details should be provided in the request body in JSON format 8 | - If the update is successful, the server should respond with the updated booking details and a status of "OK" (200) 9 | - If the booking ID is invalid or missing, the server should respond with a "Bad Request" error (400) 10 | - Optionally, a token can be provided in the cookie for authentication 11 | 12 | HTTP Payload contract 13 | { 14 | "bookingid": Integer, 15 | "roomid": Integer, 16 | "firstname": "string", 17 | "lastname": "string", 18 | "depositpaid": boolean, 19 | "email": "string", 20 | "phone": "string", 21 | "bookingdates": { 22 | "checkin": "string", 23 | "checkout": "string" 24 | } 25 | } -------------------------------------------------------------------------------- /chapter-11/src/main/resources/data/put-branding.txt: -------------------------------------------------------------------------------- 1 | As a guest 2 | In order to update branding information 3 | I want to be able to send a PUT request to /branding/ with necessary parameters 4 | 5 | Acceptance criteria 6 | * I should be able to send a PUT request to /branding/ with the necessary parameters including the branding information in the request body and an optional token in the cookie. 7 | * If the request is successful, the response status should be 200 OK. 8 | * If the request is unsuccessful due to bad parameters or missing data, the response status should be 400 Bad Request. 9 | * The request body should contain valid JSON data conforming to the schema defined in the Swagger JSON. 10 | 11 | HTTP Payload contract 12 | { 13 | "name": "string", 14 | "map": { 15 | "latitude": integer, 16 | "longitude": integer 17 | }, 18 | "logoUrl": "string", 19 | "description": "string", 20 | "contact": { 21 | "name": "string", 22 | "address": "string", 23 | "phone": "string", 24 | "email": "string" 25 | } 26 | } -------------------------------------------------------------------------------- /chapter-4/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | demo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 18 13 | 18 14 | UTF-8 15 | 16 | 17 | 18 | 19 | 20 | org.junit.jupiter 21 | junit-jupiter-engine 22 | 5.9.2 23 | test 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /chapter-5/src/test/java/com/example/pageobjects/MessagePage.java: -------------------------------------------------------------------------------- 1 | package com.example.pageobjects; 2 | 3 | import org.openqa.selenium.By; 4 | import org.openqa.selenium.WebDriver; 5 | import org.openqa.selenium.WebElement; 6 | import org.openqa.selenium.support.FindBy; 7 | import org.openqa.selenium.support.PageFactory; 8 | import org.openqa.selenium.support.ui.ExpectedConditions; 9 | import org.openqa.selenium.support.ui.WebDriverWait; 10 | 11 | import java.time.Duration; 12 | import java.util.List; 13 | 14 | public class MessagePage { 15 | private WebDriver driver; 16 | private WebDriverWait wait; 17 | 18 | @FindBy(className = "detail") 19 | private List messageList; 20 | 21 | public MessagePage(WebDriver driver) { 22 | this.driver = driver; 23 | this.wait = new WebDriverWait(driver, Duration.ofSeconds(10)); // Adjust the timeout as needed 24 | PageFactory.initElements(driver, this); 25 | } 26 | 27 | public int getMessageCount() { 28 | wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("detail"))); 29 | return messageList.size(); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /chapter-7/src/test/java/com/example/pageobjects/MessagePage.java: -------------------------------------------------------------------------------- 1 | package com.example.pageobjects; 2 | 3 | import org.openqa.selenium.By; 4 | import org.openqa.selenium.WebDriver; 5 | import org.openqa.selenium.WebElement; 6 | import org.openqa.selenium.support.FindBy; 7 | import org.openqa.selenium.support.PageFactory; 8 | import org.openqa.selenium.support.ui.ExpectedConditions; 9 | import org.openqa.selenium.support.ui.WebDriverWait; 10 | 11 | import java.time.Duration; 12 | import java.util.List; 13 | 14 | public class MessagePage { 15 | private WebDriver driver; 16 | private WebDriverWait wait; 17 | 18 | @FindBy(className = "detail") 19 | private List messageList; 20 | 21 | public MessagePage(WebDriver driver) { 22 | this.driver = driver; 23 | this.wait = new WebDriverWait(driver, Duration.ofSeconds(10)); // Adjust the timeout as needed 24 | PageFactory.initElements(driver, this); 25 | } 26 | 27 | public int getMessageCount() { 28 | wait.until(ExpectedConditions.visibilityOfElementLocated(By.className("detail"))); 29 | return messageList.size(); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /chapter-5/src/test/java/com/example/pageobjects/LoginFormPage.java: -------------------------------------------------------------------------------- 1 | package com.example.pageobjects; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.FindBy; 6 | import org.openqa.selenium.support.PageFactory; 7 | 8 | public class LoginFormPage { 9 | // Form fields 10 | @FindBy(id = "username") 11 | private WebElement usernameField; 12 | 13 | @FindBy(id = "password") 14 | private WebElement passwordField; 15 | 16 | @FindBy(id = "doLogin") 17 | private WebElement loginButton; 18 | 19 | // WebDriver instance 20 | private WebDriver driver; 21 | 22 | // Constructor 23 | public LoginFormPage(WebDriver driver) { 24 | this.driver = driver; 25 | PageFactory.initElements(driver, this); 26 | } 27 | 28 | // Methods to interact with the form fields 29 | public void enterUsername(String username) { 30 | usernameField.sendKeys(username); 31 | } 32 | 33 | public void enterPassword(String password) { 34 | passwordField.sendKeys(password); 35 | } 36 | 37 | public void clickLoginButton() { 38 | loginButton.click(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /chapter-7/src/test/java/com/example/pageobjects/LoginPage.java: -------------------------------------------------------------------------------- 1 | package com.example.pageobjects; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.FindBy; 6 | import org.openqa.selenium.support.PageFactory; 7 | public class LoginPage { 8 | 9 | // WebDriver instance 10 | private WebDriver driver; 11 | 12 | // Constructor to initialize the PageFactory 13 | public LoginPage(WebDriver driver) { 14 | this.driver = driver; 15 | PageFactory.initElements(driver, this); 16 | } 17 | 18 | // WebElements for the form fields 19 | @FindBy(id = "username") 20 | private WebElement usernameInput; 21 | 22 | @FindBy(id = "password") 23 | private WebElement passwordInput; 24 | 25 | @FindBy(id = "doLogin") 26 | private WebElement loginButton; 27 | 28 | // Methods to interact with the form 29 | public void enterUsername(String username) { 30 | usernameInput.sendKeys(username); 31 | } 32 | 33 | public void enterPassword(String password) { 34 | passwordInput.sendKeys(password); 35 | } 36 | 37 | public void clickLoginButton() { 38 | loginButton.click(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /chapter-9/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | chapter-9 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 18 13 | 18 14 | UTF-8 15 | 16 | 17 | 18 | 19 | dev.langchain4j 20 | langchain4j-open-ai 21 | 0.31.0 22 | 23 | 24 | dev.langchain4j 25 | langchain4j 26 | 0.31.0 27 | 28 | 29 | com.h2database 30 | h2 31 | 2.2.224 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /chapter-11/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | rag-demo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 18 13 | 18 14 | UTF-8 15 | 16 | 17 | 18 | 19 | commons-io 20 | commons-io 21 | 2.16.1 22 | 23 | 24 | org.apache.commons 25 | commons-text 26 | 1.12.0 27 | 28 | 29 | dev.langchain4j 30 | langchain4j-open-ai 31 | 0.31.0 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /chapter-7/src/test/java/com/example/requests/MessageRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.requests; 2 | 3 | import org.springframework.http.HttpHeaders; 4 | import org.springframework.http.HttpMethod; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.http.RequestEntity; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | import java.net.URI; 10 | 11 | public class MessageRequest { 12 | 13 | public void sendRequest(MessagePayload payload) { 14 | // Create a RestTemplate instance 15 | RestTemplate restTemplate = new RestTemplate(); 16 | 17 | // Set the request URL 18 | String url = "https://automationintesting.online/message/"; 19 | 20 | // Set the request headers 21 | HttpHeaders headers = new HttpHeaders(); 22 | headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); 23 | headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); 24 | 25 | // Create the request entity with the payload and headers 26 | RequestEntity requestEntity = new RequestEntity<>( 27 | payload, 28 | headers, 29 | HttpMethod.POST, 30 | URI.create(url) 31 | ); 32 | 33 | // Send the HTTP request 34 | restTemplate.exchange(requestEntity, Void.class); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /chapter-12/src/main/java/JsonlExporter.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedWriter; 2 | import java.io.FileWriter; 3 | import java.io.IOException; 4 | import java.util.List; 5 | 6 | public class JsonlExporter { 7 | 8 | public static void exportToJsonL(List entries, String filePath) throws IOException { 9 | try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) { 10 | // Write each JsonLEntry to the JSONL file 11 | for (JsonlEntry entry : entries) { 12 | // Start a new JSON object for each entry 13 | writer.write("{"); 14 | 15 | // Write instruction field 16 | writer.write("\"instruction\": \"" + escape(entry.getInstruction()) + "\","); 17 | 18 | // Write output field 19 | writer.write("\"output\": \"" + escape(entry.getOutput()) + "\""); 20 | 21 | // End the JSON object 22 | writer.write("}\n"); 23 | } 24 | } 25 | } 26 | 27 | // Helper method to escape special characters in JSON strings 28 | private static String escape(String str) { 29 | return str.replace("\\", "\\\\") 30 | .replace("\"", "\\\"") 31 | .replace("\n", "\\n") 32 | .replace("\r", "\\r") 33 | .replace("\t", "\\t"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter-6/gpt-api-project/src/test/java/com/example/datamanager/ContactFormDetails.java: -------------------------------------------------------------------------------- 1 | package com.example.datamanager; 2 | 3 | public class ContactFormDetails { 4 | 5 | private String name; 6 | private String email; 7 | private String phone; 8 | 9 | private String subject; 10 | 11 | private String description; 12 | 13 | public ContactFormDetails(String name, String email, String phone, String subject, String description) { 14 | this.name = name; 15 | this.email = email; 16 | this.phone = phone; 17 | this.subject = subject; 18 | this.description = description; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public String getEmail() { 26 | return email; 27 | } 28 | 29 | public String getPhone() { 30 | return phone; 31 | } 32 | 33 | public String getSubject() { 34 | return subject; 35 | } 36 | 37 | public String getDescription() { 38 | return description; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "ContactFormDetails{" + 44 | "name='" + name + '\'' + 45 | ", email='" + email + '\'' + 46 | ", phone='" + phone + '\'' + 47 | ", subject='" + subject + '\'' + 48 | ", description='" + description + '\'' + 49 | '}'; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /chapter-4/src/test/java/com/example/TimesheetTest.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | 7 | public class TimesheetTest { 8 | 9 | // Test that when a timesheet is submitted with a project name and hours it returns true 10 | @Test 11 | public void testSubmitTimesheetWithProjectNameAndHours() { 12 | Timesheet timesheet = new Timesheet(); 13 | boolean result = timesheet.submitTimesheet("Project 1", 8); 14 | assertEquals(true, result); 15 | } 16 | 17 | // Test that when timesheets are added they can be retrieved as a list 18 | @Test 19 | public void testAddTimesheetsToList() { 20 | Timesheet timesheet = new Timesheet(); 21 | timesheet.submitTimesheet("Project 1", 8); 22 | timesheet.submitTimesheet("Project 2", 8); 23 | timesheet.submitTimesheet("Project 3", 8); 24 | assertEquals(3, timesheet.getTimesheets().size()); 25 | } 26 | 27 | // Test that the total hours worked can be calculated from a list of timesheets from one project 28 | @Test 29 | public void testCalculateTotalHoursWorked() { 30 | Timesheet timesheet = new Timesheet(); 31 | timesheet.submitTimesheet("Project 1", 8); 32 | timesheet.submitTimesheet("Project 1", 8); 33 | timesheet.submitTimesheet("Project 1", 8); 34 | 35 | Long total = timesheet.getTotalTimesheetHours("Project 1"); 36 | 37 | assertEquals(24, total); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /chapter-5/src/test/java/com/example/requests/MessagePayload.java: -------------------------------------------------------------------------------- 1 | package com.example.requests; 2 | 3 | public class MessagePayload { 4 | private String name; 5 | private String email; 6 | private String phone; 7 | private String subject; 8 | private String description; 9 | 10 | public MessagePayload() { 11 | } 12 | 13 | public MessagePayload(String name, String email, String phone, String subject, String description) { 14 | this.name = name; 15 | this.email = email; 16 | this.phone = phone; 17 | this.subject = subject; 18 | this.description = description; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | 29 | public String getEmail() { 30 | return email; 31 | } 32 | 33 | public void setEmail(String email) { 34 | this.email = email; 35 | } 36 | 37 | public String getPhone() { 38 | return phone; 39 | } 40 | 41 | public void setPhone(String phone) { 42 | this.phone = phone; 43 | } 44 | 45 | public String getSubject() { 46 | return subject; 47 | } 48 | 49 | public void setSubject(String subject) { 50 | this.subject = subject; 51 | } 52 | 53 | public String getDescription() { 54 | return description; 55 | } 56 | 57 | public void setDescription(String description) { 58 | this.description = description; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /chapter-7/src/test/java/com/example/requests/MessagePayload.java: -------------------------------------------------------------------------------- 1 | package com.example.requests; 2 | 3 | public class MessagePayload { 4 | private String name; 5 | private String email; 6 | private String phone; 7 | private String subject; 8 | private String description; 9 | 10 | public MessagePayload() { 11 | } 12 | 13 | public MessagePayload(String name, String email, String phone, String subject, String description) { 14 | this.name = name; 15 | this.email = email; 16 | this.phone = phone; 17 | this.subject = subject; 18 | this.description = description; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | 29 | public String getEmail() { 30 | return email; 31 | } 32 | 33 | public void setEmail(String email) { 34 | this.email = email; 35 | } 36 | 37 | public String getPhone() { 38 | return phone; 39 | } 40 | 41 | public void setPhone(String phone) { 42 | this.phone = phone; 43 | } 44 | 45 | public String getSubject() { 46 | return subject; 47 | } 48 | 49 | public void setSubject(String subject) { 50 | this.subject = subject; 51 | } 52 | 53 | public String getDescription() { 54 | return description; 55 | } 56 | 57 | public void setDescription(String description) { 58 | this.description = description; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /chapter-7/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | chapter-7 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 18 13 | 18 14 | UTF-8 15 | 16 | 17 | 18 | 19 | org.junit.jupiter 20 | junit-jupiter-engine 21 | 5.9.2 22 | test 23 | 24 | 25 | org.seleniumhq.selenium 26 | selenium-java 27 | 4.22.0 28 | test 29 | 30 | 31 | io.github.bonigarcia 32 | webdrivermanager 33 | 5.9.1 34 | test 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 3.3.1 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /chapter-5/src/test/java/com/example/pageobjects/ContactFormPage.java: -------------------------------------------------------------------------------- 1 | package com.example.pageobjects; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.FindBy; 6 | import org.openqa.selenium.support.PageFactory; 7 | 8 | public class ContactFormPage { 9 | 10 | // Form fields 11 | @FindBy(id = "name") 12 | private WebElement nameField; 13 | 14 | @FindBy(id = "email") 15 | private WebElement emailField; 16 | 17 | @FindBy(id = "phone") 18 | private WebElement phoneField; 19 | 20 | @FindBy(id = "subject") 21 | private WebElement subjectField; 22 | 23 | @FindBy(id = "description") 24 | private WebElement descriptionField; 25 | 26 | @FindBy(id = "submitContact") 27 | private WebElement submitButton; 28 | 29 | // WebDriver instance 30 | private WebDriver driver; 31 | 32 | // Constructor 33 | public ContactFormPage(WebDriver driver) { 34 | this.driver = driver; 35 | PageFactory.initElements(driver, this); 36 | } 37 | 38 | // Methods to interact with the form fields 39 | public void enterName(String name) { 40 | nameField.sendKeys(name); 41 | } 42 | 43 | public void enterEmail(String email) { 44 | emailField.sendKeys(email); 45 | } 46 | 47 | public void enterPhone(String phone) { 48 | phoneField.sendKeys(phone); 49 | } 50 | 51 | public void enterSubject(String subject) { 52 | subjectField.sendKeys(subject); 53 | } 54 | 55 | public void enterDescription(String description) { 56 | descriptionField.sendKeys(description); 57 | } 58 | 59 | public void clickSubmitButton() { 60 | submitButton.click(); 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /chapter-6/gpt-api-project/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | gpt-api-project 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 18 13 | 18 14 | UTF-8 15 | 16 | 17 | 18 | 19 | 20 | org.junit.jupiter 21 | junit-jupiter-engine 22 | 5.9.2 23 | test 24 | 25 | 26 | 27 | org.seleniumhq.selenium 28 | selenium-java 29 | 4.22.0 30 | test 31 | 32 | 33 | io.github.bonigarcia 34 | webdrivermanager 35 | 5.9.1 36 | test 37 | 38 | 39 | dev.langchain4j 40 | langchain4j-open-ai 41 | 0.31.0 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /chapter-7/src/test/java/com/example/pageobjects/ContactFormPage.java: -------------------------------------------------------------------------------- 1 | package com.example.pageobjects; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.FindBy; 6 | import org.openqa.selenium.support.PageFactory; 7 | 8 | public class ContactFormPage { 9 | 10 | // WebDriver instance 11 | private WebDriver driver; 12 | 13 | // Constructor to initialize the PageFactory 14 | public ContactFormPage(WebDriver driver) { 15 | this.driver = driver; 16 | PageFactory.initElements(driver, this); 17 | } 18 | 19 | // WebElements for the form fields 20 | @FindBy(id = "name") 21 | private WebElement nameInput; 22 | 23 | @FindBy(id = "email") 24 | private WebElement emailInput; 25 | 26 | @FindBy(id = "phone") 27 | private WebElement phoneInput; 28 | 29 | @FindBy(id = "subject") 30 | private WebElement subjectInput; 31 | 32 | @FindBy(id = "description") 33 | private WebElement descriptionTextarea; 34 | 35 | @FindBy(id = "submitContact") 36 | private WebElement submitButton; 37 | 38 | // Methods to interact with the form 39 | public void enterName(String name) { 40 | nameInput.sendKeys(name); 41 | } 42 | 43 | public void enterEmail(String email) { 44 | emailInput.sendKeys(email); 45 | } 46 | 47 | public void enterPhone(String phone) { 48 | phoneInput.sendKeys(phone); 49 | } 50 | 51 | public void enterSubject(String subject) { 52 | subjectInput.sendKeys(subject); 53 | } 54 | 55 | public void enterDescription(String description) { 56 | descriptionTextarea.sendKeys(description); 57 | } 58 | 59 | public void clickSubmitButton() { 60 | submitButton.click(); 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /chapter-5/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | chapter-5 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 18 13 | 18 14 | UTF-8 15 | 16 | 17 | 18 | 19 | org.junit.jupiter 20 | junit-jupiter-engine 21 | 5.9.2 22 | test 23 | 24 | 25 | org.seleniumhq.selenium 26 | selenium-java 27 | 4.9.1 28 | test 29 | 30 | 31 | io.github.bonigarcia 32 | webdrivermanager 33 | 5.3.3 34 | test 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 3.1.0 42 | 43 | 44 | 45 | 46 | com.applitools 47 | eyes-selenium-java5 48 | 5.52.0 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /chapter-5/src/test/java/com/example/requests/MessageRequest.java: -------------------------------------------------------------------------------- 1 | package com.example.requests; 2 | 3 | import org.springframework.http.HttpHeaders; 4 | import org.springframework.http.HttpMethod; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.http.RequestEntity; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | import java.net.URI; 10 | 11 | public class MessageRequest { 12 | 13 | public void sendRequest(MessagePayload payload) { 14 | // Create a RestTemplate instance, which is used to make HTTP requests 15 | RestTemplate restTemplate = new RestTemplate(); 16 | 17 | // Define the URL to which the HTTP request will be sent 18 | String url = "https://automationintesting.online/message/"; 19 | 20 | // Create an HttpHeaders object to store the headers for the request 21 | HttpHeaders headers = new HttpHeaders(); 22 | 23 | // Set the "Accept" header to specify that the client expects JSON in response 24 | headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); 25 | 26 | // Set the "Content-Type" header to specify that the request body will be in JSON format 27 | headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); 28 | 29 | // Create a RequestEntity, which encapsulates the request payload, headers, HTTP method, and the target URI 30 | RequestEntity requestEntity = new RequestEntity<>( 31 | payload, // The request body (payload) to be sent 32 | headers, // The HTTP headers (including content type and accept type) 33 | HttpMethod.POST, // The HTTP method (in this case, POST) 34 | URI.create(url) // The URI to send the request to 35 | ); 36 | 37 | // Use the RestTemplate to send the HTTP request, with the response type set to Void (we don't expect a response body) 38 | restTemplate.exchange(requestEntity, Void.class); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /chapter-6/gpt-api-project/src/test/java/com/example/pageobjects/ContactFormPage.java: -------------------------------------------------------------------------------- 1 | package com.example.pageobjects; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.FindBy; 6 | import org.openqa.selenium.support.PageFactory; 7 | import org.openqa.selenium.support.ui.WebDriverWait; 8 | 9 | import java.time.Duration; 10 | 11 | public class ContactFormPage { 12 | 13 | // Form fields 14 | @FindBy(id = "name") 15 | private WebElement nameField; 16 | 17 | @FindBy(id = "email") 18 | private WebElement emailField; 19 | 20 | @FindBy(id = "phone") 21 | private WebElement phoneField; 22 | 23 | @FindBy(id = "subject") 24 | private WebElement subjectField; 25 | 26 | @FindBy(id = "description") 27 | private WebElement descriptionField; 28 | 29 | @FindBy(id = "submitContact") 30 | private WebElement submitButton; 31 | 32 | @FindBy(css = ".contact h2") 33 | private WebElement successMessage; 34 | 35 | // WebDriver instance 36 | private WebDriver driver; 37 | 38 | // Constructor 39 | public ContactFormPage(WebDriver driver) { 40 | this.driver = driver; 41 | PageFactory.initElements(driver, this); 42 | } 43 | 44 | // Methods to interact with the form fields 45 | public void enterName(String name) { 46 | nameField.sendKeys(name); 47 | } 48 | 49 | public void enterEmail(String email) { 50 | emailField.sendKeys(email); 51 | } 52 | 53 | public void enterPhone(String phone) { 54 | phoneField.sendKeys(phone); 55 | } 56 | 57 | public void enterSubject(String subject) { 58 | subjectField.sendKeys(subject); 59 | } 60 | 61 | public void enterDescription(String description) { 62 | descriptionField.sendKeys(description); 63 | } 64 | 65 | public String getSuccessMessage() { 66 | WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(5)); 67 | wait.until((d) -> successMessage.isDisplayed()); 68 | return successMessage.getText(); 69 | } 70 | public void clickSubmitButton() { 71 | submitButton.click(); 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /chapter-5/src/test/java/com/example/tests/InitialMessageTest.java: -------------------------------------------------------------------------------- 1 | package com.example.tests; 2 | 3 | import com.example.pageobjects.ContactFormPage; 4 | import com.example.pageobjects.LoginFormPage; 5 | import com.example.pageobjects.MessagePage; 6 | import com.example.requests.MessagePayload; 7 | import com.example.requests.MessageRequest; 8 | import io.github.bonigarcia.wdm.WebDriverManager; 9 | import org.junit.jupiter.api.AfterAll; 10 | import org.junit.jupiter.api.BeforeAll; 11 | import org.junit.jupiter.api.Test; 12 | import org.openqa.selenium.WebDriver; 13 | import org.openqa.selenium.chrome.ChromeDriver; 14 | 15 | import static org.junit.jupiter.api.Assertions.assertEquals; 16 | 17 | public class InitialMessageTest { 18 | 19 | private static WebDriver driver; 20 | 21 | // Use WebDriverManager to download the driver binaries 22 | // and start the browser server for us. 23 | @BeforeAll 24 | public static void setupClass() { 25 | WebDriverManager.chromedriver().setup(); 26 | 27 | driver = new ChromeDriver(); 28 | } 29 | 30 | @AfterAll 31 | public static void teardown() { 32 | driver.quit(); 33 | } 34 | 35 | @Test 36 | public void testMessageIsCreated() { 37 | driver.get("https://automationintesting.online/#/"); 38 | 39 | ContactFormPage contactFormPage = new ContactFormPage(driver); 40 | contactFormPage.enterName("John Smith"); 41 | contactFormPage.enterEmail("test@email.com"); 42 | contactFormPage.enterPhone("07123456789"); 43 | contactFormPage.enterSubject("Testing"); 44 | contactFormPage.enterDescription("This is a test message"); 45 | contactFormPage.clickSubmitButton(); 46 | 47 | driver.get("https://automationintesting.online/#/admin/"); 48 | 49 | LoginFormPage loginFormPage = new LoginFormPage(driver); 50 | loginFormPage.enterUsername("admin"); 51 | loginFormPage.enterPassword("password"); 52 | loginFormPage.clickLoginButton(); 53 | 54 | driver.get("https://automationintesting.online/#/admin/messages"); 55 | 56 | MessagePage messagePage = new MessagePage(driver); 57 | assertEquals(2, messagePage.getMessageCount()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Software Testing with Generative AI 2 | 3 | This repository contains all the supporting prompts and code for my book [Software Testing with Generative AI](https://www.manning.com/books/software-testing-with-generative-ai?utm_source=winteringham&utm_medium=affiliate&utm_campaign=book_winteringham2_ai_12_13_23). 4 | 5 | ## What does the book cover? 6 | 7 | The more you test, the more you learn about your software. Software Testing with Generative AI shows you how you can expand, automate, and enhance your testing with Large Language Model (LLM)-based AI. Your team will soon be delivering higher quality tests, all in less time. 8 | 9 | Inside Software Testing with Generative AI you’ll learn how to: 10 | 11 | * Spot opportunities to improve test quality with AI 12 | * Construct test automation with the support of AI tools 13 | * Formulate new ideas during exploratory testing using AI tools 14 | * Use AI tools to aid the design process of new features 15 | * Improve the testability of a context with the help of AI tools 16 | * Maximize your output with prompt engineering 17 | * Create custom LLMs for your business’s specific needs 18 | 19 | Software Testing with Generative AI is full of hype-free advice for supporting your software testing with AI. Inside, you’ll find strategies from bestselling author Mark Winteringham to generate synthetic testing data, implement automation, and even augment and improve your test design with AI. 20 | 21 | In Software Testing with Generative AI, you’ll explore almost every aspect of testing—automation, test data management, test scripting, exploratory testing, and more—and learn how AI can assist and enhance each one. Each example is rooted in the kind of testing problems you’ll encounter every day. See how you can use GitHub CoPilot to guide your test-driven development, get meaningful code feedback from ChatGPT, and use the OpenAI API to integrate AI into your data generation. You’ll master best practices for prompt engineering and even learn how to enhance an open source LLM for your team’s precise requirements. Soon, you’ll have the best of both worlds—higher quality testing that takes up less of your time! 22 | 23 | ## Where can I get a copy? 24 | 25 | Available at the following stores: 26 | * [Manning Publishing](https://www.manning.com/books/software-testing-with-generative-ai?utm_source=winteringham&utm_medium=affiliate&utm_campaign=book_winteringham2_ai_12_13_23) -------------------------------------------------------------------------------- /chapter-9/src/main/java/DataAssistant.java: -------------------------------------------------------------------------------- 1 | // Importing necessary classes from the OpenAI and Langchain4j libraries. 2 | import dev.langchain4j.model.openai.OpenAiChatModel; 3 | import dev.langchain4j.model.openai.OpenAiChatModelName; 4 | import dev.langchain4j.service.AiServices; 5 | 6 | import java.sql.SQLException; 7 | import java.util.Scanner; 8 | 9 | public class DataAssistant { 10 | 11 | // Defining an interface that declares a method for sending prompts to the AI service. 12 | interface DataAssistantService { 13 | String sendPrompt(String userPrompt); 14 | } 15 | 16 | public static void main(String[] args) throws SQLException { 17 | 18 | // Creating an instance of the OpenAiChatModel with a builder pattern. 19 | // Set the API key (replace "ENTER_API_KEY" with a valid one) and specify the model name. 20 | OpenAiChatModel model = OpenAiChatModel 21 | .builder() 22 | .apiKey("ENTER_API_KEY") // API key required for authenticating with OpenAI's API 23 | .modelName(OpenAiChatModelName.GPT_3_5_TURBO) // Using GPT-3.5-turbo model for chat 24 | .build(); 25 | 26 | // Building the AI service for the DataAssistant using Langchain4j. 27 | // This links the created model with the service that will interact with it. 28 | DataAssistantService dataAssistantChat = AiServices.builder(DataAssistantService.class) 29 | .chatLanguageModel(model) // Assigning the OpenAi model to the service 30 | .tools(new DataAssistantTools()) // Adding any tools that can be used (must implement this class) 31 | .build(); 32 | 33 | // Starting an infinite loop to keep the program running for user interaction. 34 | while(true) { 35 | // Setting up a scanner to capture user input from the console. 36 | Scanner scanner = new Scanner(System.in); 37 | System.out.println("What do you need?"); // Prompting the user for input 38 | 39 | // Reading the user input as a string (the query/prompt). 40 | String query = scanner.nextLine(); 41 | 42 | // Sending the prompt to the AI service and getting the response. 43 | String response = dataAssistantChat.sendPrompt(query); 44 | 45 | // Outputting the AI's response to the console. 46 | System.out.println(response); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /chapter-4/src/main/java/com/example/Timesheet.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import java.util.*; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | public class Timesheet { 7 | 8 | // A thread-safe map to store project names and corresponding timesheet hours. 9 | // The key is the project name (String), and the value is the duration in hours (Long). 10 | private ConcurrentHashMap timesheets = new ConcurrentHashMap<>(); 11 | 12 | /** 13 | * Submits a timesheet entry for a project. 14 | * 15 | * @param projectName The name of the project to submit time for. 16 | * @param duration The duration (in hours) spent on the project. 17 | * @return boolean Returns true if the timesheet entry is valid and submitted, false otherwise. 18 | */ 19 | public boolean submitTimesheet(String projectName, long duration) { 20 | // Validate that project name is not null and duration is a positive number. 21 | if (projectName != null && duration > 0) { 22 | // Convert project name to lowercase to ensure case-insensitivity when storing. 23 | projectName = projectName.toLowerCase(); 24 | 25 | // If the project already exists in the map, add the duration to the existing value. 26 | // Otherwise, initialize the project with the new duration. 27 | timesheets.put(projectName, timesheets.getOrDefault(projectName, 0L) + duration); 28 | return true; // Successfully submitted the timesheet. 29 | } else { 30 | return false; // Invalid input, either null projectName or non-positive duration. 31 | } 32 | } 33 | 34 | /** 35 | * Retrieves all the timesheet durations. 36 | * 37 | * @return Collection A collection of all durations stored in the timesheets map. 38 | */ 39 | public Collection getTimesheets() { 40 | return timesheets.values(); 41 | } 42 | 43 | /** 44 | * Gets the total timesheet hours for a specific project. 45 | * 46 | * @param projectName The name of the project to retrieve time for. 47 | * @return long The total duration (in hours) spent on the project, or 0 if the project does not exist. 48 | */ 49 | public long getTotalTimesheetHours(String projectName) { 50 | // Retrieve the total duration for the specified project name, using case-insensitive lookup. 51 | return timesheets.getOrDefault(projectName.toLowerCase(), 0L); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /chapter-9/src/main/java/DataAssistantTools.java: -------------------------------------------------------------------------------- 1 | import dev.langchain4j.agent.tool.P; 2 | import dev.langchain4j.agent.tool.Tool; 3 | 4 | import java.sql.SQLException; 5 | 6 | public class DataAssistantTools { 7 | 8 | // Instance of QueryTools class used to interact with the database 9 | QueryTools queryTools = new QueryTools(); 10 | 11 | // Constructor that can throw a SQLException, potentially from initializing the QueryTools 12 | public DataAssistantTools() throws SQLException { 13 | } 14 | 15 | // Tool method to create room records in the database 16 | // The annotation @Tool specifies that this method can be invoked as a tool, with 'count' passed by the caller 17 | @Tool("Create room records") 18 | public void createRooms(@P("Amount of room records to create") int count) throws SQLException { 19 | // Loop through the number of rooms to be created, calling the createRoom method for each 20 | for (int i = 1; i <= count; i++) { 21 | queryTools.createRoom(); // Interacts with QueryTools to create a new room in the database 22 | } 23 | } 24 | 25 | // Tool method to get the most recent room ID from the database 26 | // This can be useful after room creation to work with the latest room entry 27 | @Tool("Get most recent roomid from database after rooms have been created") 28 | public int getRoomId() throws SQLException { 29 | return queryTools.getRoomId(); // Fetches the most recently created room ID from the database 30 | } 31 | 32 | // Tool method to create booking records linked to a specific room ID 33 | // The room ID is passed along with the count of booking records to create 34 | @Tool("Create booking records") 35 | public void createBookings(@P("Amount of booking records to create") int count, @P("Most recent roomid") int roomid) throws SQLException { 36 | // Inform the user which room ID is being used for the bookings 37 | System.out.println("I will create the bookings for room: " + roomid); 38 | 39 | // Loop through the number of bookings to be created, calling the createBooking method for each 40 | for (int i = 1; i <= count; i++) { 41 | queryTools.createBooking(roomid); // Interacts with QueryTools to create a booking for the given room ID 42 | } 43 | } 44 | 45 | // Tool method to display the current state of the ROOM and BOOKING tables in the database 46 | @Tool("Show results of database") 47 | public void displayDatabase() throws SQLException { 48 | // Output all data from the ROOMS table 49 | System.out.println("Current ROOM database state:"); 50 | queryTools.outputTables("SELECT * FROM ROOMS"); 51 | 52 | // Output all data from the BOOKINGS table 53 | System.out.println("Current BOOKING database state:"); 54 | queryTools.outputTables("SELECT * FROM BOOKINGS"); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /chapter-5/prompts/contact-us-form-prompt.txt: -------------------------------------------------------------------------------- 1 | Create a page object in Java using the @FindBy annotation to represent the contact form page. Use the provided HTML delimited by three hashes as a reference to identify the form fields. 2 | 3 | 1. Create a new Java class for the contact form page object. 4 | 5 | 2. Import org.openqa.selenium.support.FindBy and org.openqa.selenium.WebElement. 6 | 7 | 3. Annotate the class with @FindBy to represent the contact form. 8 | 9 | 4. Declare private WebElement variables for each form field using @FindBy. 10 | 11 | 5. Inspect the HTML form to identify attributes that can uniquely locate each form field. 12 | 13 | 6. Annotate each form field variable with @FindBy, specifying the unique attribute and value. 14 | 15 | 7. Create a constructor that takes a WebDriver parameter. 16 | 17 | 8. Inside the constructor, call PageFactory.initElements(driver, this) to initialize the annotated elements. 18 | 19 | 9. Implement public methods in the page object to interact with the form fields, using the initialized elements. 20 | 21 | 10. Use the initialized form field elements directly, without driver.findElement(). 22 | 23 | 11. Optionally, add additional methods for specific actions or retrieving information from the form. 24 | 25 | ### 26 |
27 |
28 |
29 | 30 | 31 | 32 |
33 | 34 |
35 |
36 |
37 | 38 | 39 | 40 |
41 | 42 |
43 |
44 |
45 | 46 | 47 | 48 |
49 | 50 |
51 |
52 |
53 | 54 | 55 | 56 |
57 | 58 |
59 |
60 |
61 | Message 62 |
63 | 64 |
65 |
66 | 67 |
68 | ### -------------------------------------------------------------------------------- /chapter-7/src/test/java/com/example/tests/InitialMessageTest.java: -------------------------------------------------------------------------------- 1 | package com.example.tests; 2 | 3 | // Importing the necessary classes and libraries for the test 4 | import com.example.pageobjects.ContactFormPage; 5 | import com.example.pageobjects.LoginPage; 6 | import com.example.pageobjects.MessagePage; 7 | import io.github.bonigarcia.wdm.WebDriverManager; 8 | import org.junit.jupiter.api.AfterAll; 9 | import org.junit.jupiter.api.BeforeAll; 10 | import org.junit.jupiter.api.Test; 11 | import org.openqa.selenium.WebDriver; 12 | import org.openqa.selenium.chrome.ChromeDriver; 13 | 14 | import static org.junit.jupiter.api.Assertions.assertEquals; 15 | 16 | public class InitialMessageTest { 17 | 18 | // Declare the WebDriver instance that will be used to control the browser 19 | private static WebDriver driver; 20 | 21 | // This method is run once before all the test methods in this class. 22 | // It sets up the WebDriver (ChromeDriver in this case) using WebDriverManager. 23 | @BeforeAll 24 | public static void setupClass() { 25 | // WebDriverManager takes care of automatically downloading the correct driver binary 26 | // and configuring it for the desired browser (Chrome in this case). 27 | WebDriverManager.chromedriver().setup(); 28 | 29 | // Initialize the WebDriver object with ChromeDriver (which launches a Chrome browser). 30 | driver = new ChromeDriver(); 31 | } 32 | 33 | // This method is run after all test methods have been executed. 34 | // It ensures that the browser is properly closed and cleaned up. 35 | @AfterAll 36 | public static void teardown() { 37 | // Quit the browser after the test execution is done to free up resources. 38 | driver.quit(); 39 | } 40 | 41 | // The main test method that checks if a message is successfully created and displayed. 42 | @Test 43 | public void testMessageIsCreated() { 44 | // Navigate to the target website where the test will be executed. 45 | driver.get("https://automationintesting.online/#/"); 46 | 47 | // Instantiate the ContactFormPage object to interact with the contact form. 48 | ContactFormPage contactFormPage = new ContactFormPage(driver); 49 | 50 | // Fill out the contact form by entering the required fields. 51 | contactFormPage.enterName("John Smith"); 52 | contactFormPage.enterEmail("test@email.com"); 53 | contactFormPage.enterPhone("07123456789"); 54 | contactFormPage.enterSubject("Testing"); 55 | contactFormPage.enterDescription("This is a test message"); 56 | 57 | // Submit the contact form. 58 | contactFormPage.clickSubmitButton(); 59 | 60 | // Navigate to the admin login page. 61 | driver.get("https://automationintesting.online/#/admin/"); 62 | 63 | // Instantiate the LoginPage object and enter the login credentials. 64 | LoginPage loginPage = new LoginPage(driver); 65 | loginPage.enterUsername("admin"); 66 | loginPage.enterPassword("password"); 67 | 68 | // Log into the admin panel. 69 | loginPage.clickLoginButton(); 70 | 71 | // Navigate to the admin messages page to check for the newly created message. 72 | driver.get("https://automationintesting.online/#/admin/messages"); 73 | 74 | // Instantiate the MessagePage object to interact with the messages section. 75 | MessagePage messagePage = new MessagePage(driver); 76 | 77 | // Assert that there are two messages in the message list (this could mean that 78 | // there was already 1 message present before, and after submitting the new one, 79 | // the count becomes 2). 80 | assertEquals(2, messagePage.getMessageCount()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /chapter-6/gpt-api-project/src/test/java/com/example/checks/ExampleTests.java: -------------------------------------------------------------------------------- 1 | package com.example.checks; 2 | 3 | // Import necessary libraries and classes 4 | import com.example.datamanager.ContactFormDetails; 5 | import com.example.pageobjects.ContactFormPage; 6 | import com.google.gson.Gson; 7 | import dev.langchain4j.model.openai.OpenAiChatModel; 8 | import io.github.bonigarcia.wdm.WebDriverManager; 9 | import org.junit.jupiter.api.AfterAll; 10 | import org.junit.jupiter.api.BeforeAll; 11 | import org.junit.jupiter.api.Test; 12 | import org.openqa.selenium.WebDriver; 13 | import org.openqa.selenium.chrome.ChromeDriver; 14 | 15 | public class ExampleTests { 16 | 17 | // Declaring the WebDriver instance 18 | private static WebDriver driver; 19 | 20 | // This method sets up the Chrome WebDriver before all tests run 21 | @BeforeAll 22 | public static void setupChromeDriver(){ 23 | // Set up the Chrome WebDriver using WebDriverManager 24 | WebDriverManager.chromedriver().setup(); 25 | 26 | // Initialize the WebDriver instance with ChromeDriver 27 | driver = new ChromeDriver(); 28 | } 29 | 30 | // This method closes the Chrome WebDriver after all tests are complete 31 | @AfterAll 32 | public static void closeChromeDriver(){ 33 | // Quit the WebDriver session and close the browser 34 | driver.quit(); 35 | } 36 | 37 | // Test case for submitting the contact form with hardcoded test data 38 | @Test 39 | public void exampleContactUsFormTest() throws InterruptedException { 40 | // Navigate to the website with the contact form 41 | driver.get("https://automationintesting.online/#/"); 42 | 43 | // Initialize the page object for interacting with the contact form 44 | ContactFormPage contactFormPage = new ContactFormPage(driver); 45 | 46 | // Enter data into the contact form fields 47 | contactFormPage.enterName("John Smith"); 48 | contactFormPage.enterEmail("john@example.com"); 49 | contactFormPage.enterPhone("01234567890"); 50 | contactFormPage.enterSubject("Test Subject"); 51 | contactFormPage.enterDescription("This is a test message"); 52 | 53 | // Submit the form 54 | contactFormPage.clickSubmitButton(); 55 | 56 | // Verify that the success message is displayed after submission 57 | assert contactFormPage.getSuccessMessage().contains("Thanks for getting in touch"); 58 | } 59 | 60 | // Test case for submitting the contact form using AI-generated data 61 | @Test 62 | public void exampleContactUsFormTestWithGPT() { 63 | // Initialize the OpenAI chat model with an API key (placeholder) 64 | OpenAiChatModel model = OpenAiChatModel.withApiKey("Enter API key"); 65 | 66 | // Define the prompt to request data generation from GPT in JSON format 67 | String prompt = """ 68 | You are a data generator. Create me random data in a JSON format based on the criteria delimited by three hashes. 69 | Additional data requirements are shared between back ticks. 70 | ### 71 | name 72 | email 73 | phone `UK format` 74 | subject `Over 20 characters in length` 75 | description `Over 50 characters in length` 76 | ### 77 | """; 78 | 79 | // Use the model to generate data based on the prompt 80 | String testData = model.generate(prompt); 81 | 82 | // Convert the generated JSON data to a ContactFormDetails object 83 | ContactFormDetails contactFormDetails = new Gson().fromJson(testData, ContactFormDetails.class); 84 | 85 | // Navigate to the website with the contact form 86 | driver.get("https://automationintesting.online/#/"); 87 | 88 | // Initialize the page object for interacting with the contact form 89 | ContactFormPage contactFormPage = new ContactFormPage(driver); 90 | 91 | // Enter AI-generated data into the contact form fields 92 | contactFormPage.enterName(contactFormDetails.getName()); 93 | contactFormPage.enterEmail(contactFormDetails.getEmail()); 94 | contactFormPage.enterPhone(contactFormDetails.getPhone()); 95 | contactFormPage.enterSubject(contactFormDetails.getSubject()); 96 | contactFormPage.enterDescription(contactFormDetails.getDescription()); 97 | 98 | // Submit the form 99 | contactFormPage.clickSubmitButton(); 100 | 101 | // Verify that the success message is displayed after submission 102 | assert contactFormPage.getSuccessMessage().contains("Thanks for getting in touch"); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /chapter-11/src/main/java/CompletedRAGDemo.java: -------------------------------------------------------------------------------- 1 | import dev.langchain4j.model.openai.OpenAiChatModel; 2 | import org.apache.commons.io.FileUtils; 3 | import org.apache.commons.text.similarity.CosineDistance; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.Scanner; 10 | 11 | public class CompletedRAGDemo { 12 | 13 | /** 14 | * This method loads all the files from a specified folder inside the resources directory. 15 | * It reads the contents of each file as a string and stores it in a list. 16 | * 17 | * @param folderPath The folder path within the resources directory. 18 | * @return A list of strings, where each string contains the contents of a file. 19 | * @throws IOException If an I/O error occurs during file reading. 20 | */ 21 | public static List loadFilesFromResources(String folderPath) throws IOException { 22 | List fileContents = new ArrayList<>(); 23 | ClassLoader classLoader = CompletedRAGDemo.class.getClassLoader(); 24 | 25 | // Locate the folder within the resources directory 26 | File folder = new File(classLoader.getResource(folderPath).getFile()); 27 | 28 | // Iterate over all files in the folder and read their contents 29 | for (File file : folder.listFiles()) { 30 | if (file.isFile()) { 31 | // Read each file into a string and add it to the list 32 | String fileContent = FileUtils.readFileToString(file, "UTF-8"); 33 | fileContents.add(fileContent); 34 | } 35 | } 36 | 37 | return fileContents; 38 | } 39 | 40 | /** 41 | * This method takes a list of strings and a query string, then finds the closest match 42 | * from the list using the Cosine Similarity algorithm. The smallest cosine distance 43 | * indicates the closest match. 44 | * 45 | * @param list The list of strings to search through. 46 | * @param query The string to find the closest match for. 47 | * @return The string from the list that is the closest match to the query. 48 | */ 49 | public static String findClosestMatch(List list, String query) { 50 | String closestMatch = null; 51 | double minDistance = Double.MAX_VALUE; // Initialize with the maximum possible distance 52 | CosineDistance cosineDistance = new CosineDistance(); 53 | 54 | // Compare the query against each item in the list 55 | for (String item : list) { 56 | // Compute the cosine distance between the current item and the query 57 | double distance = cosineDistance.apply(item, query); 58 | // Update the closest match if the current item has a smaller distance 59 | if (distance < minDistance) { 60 | minDistance = distance; 61 | closestMatch = item; 62 | } 63 | } 64 | 65 | return closestMatch; 66 | } 67 | 68 | public static void main(String[] args) throws Exception { 69 | // Prompt the user for input 70 | System.out.println("What would you like help with?"); 71 | Scanner in = new Scanner(System.in); 72 | String userInput = in.nextLine(); // Capture user input 73 | 74 | // Load files from the "data" folder within the resources directory 75 | List corpus = loadFilesFromResources("data"); 76 | 77 | // Define a prompt template for generating risks based on the user story and input 78 | String prompt = """ 79 | You are an expert software tester that makes recommendations for testing ideas and risks. You answer with suggested risks to test for based off of the provided user story delimited by three hashes and user input that is delimited by three back ticks. 80 | 81 | Compile a list of suggested risks based off of the user story provided to test for based on the user story and the user input. Cite which part of the user story the risk is based off of. Check that the risk matches the part of the user story before outputting. 82 | 83 | ### 84 | {relevant_document} 85 | ### 86 | ``` 87 | {user_input} 88 | ``` 89 | """; 90 | 91 | // Find the closest matching document in the corpus based on the user input 92 | String closestMatch = findClosestMatch(corpus, userInput); 93 | 94 | // Replace placeholders in the prompt template with the closest document and user input 95 | prompt = prompt.replace("{relevant_document}", closestMatch) 96 | .replace("{user_input}", userInput); 97 | 98 | // Output the constructed prompt to the console 99 | System.out.println("Created prompt"); 100 | System.out.println(prompt); 101 | 102 | // Initialize the OpenAiChatModel with an API key for GPT model interaction 103 | OpenAiChatModel model = OpenAiChatModel.withApiKey("enter-api-key"); 104 | 105 | // Generate a response from the model based on the constructed prompt 106 | String response = model.generate(prompt); 107 | 108 | // Display the model's response in the console 109 | System.out.println("Response received:"); 110 | System.out.println(response); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /chapter-9/src/main/java/QueryTools.java: -------------------------------------------------------------------------------- 1 | import java.sql.*; 2 | 3 | public class QueryTools { 4 | 5 | // Connection object to manage the connection to the database 6 | private final Connection connection; 7 | 8 | // Constructor to initialize the connection and create the database schema 9 | public QueryTools() throws SQLException { 10 | // Establish a connection to an in-memory H2 database called "testdb" 11 | connection = DriverManager.getConnection("jdbc:h2:mem:testdb"); 12 | 13 | // Create a statement to execute SQL commands 14 | Statement st = connection.createStatement(); 15 | 16 | // Create two tables: BOOKINGS and ROOMS with appropriate columns and constraints 17 | st.executeUpdate(""" 18 | CREATE TABLE BOOKINGS ( 19 | bookingid int NOT NULL AUTO_INCREMENT, // Unique ID for each booking 20 | roomid int, // Foreign key to the ROOMS table 21 | firstname varchar(255), // First name of the person booking 22 | lastname varchar(255), // Last name of the person booking 23 | depositpaid boolean, // Whether a deposit is paid 24 | checkin date, // Check-in date 25 | checkout date, // Check-out date 26 | primary key (bookingid) // Primary key on bookingid 27 | ); 28 | CREATE TABLE ROOMS ( 29 | roomid int NOT NULL AUTO_INCREMENT, // Unique ID for each room 30 | room_name varchar(255), // Name or number of the room 31 | type varchar(255), // Type of room (single, double, etc.) 32 | beds int, // Number of beds in the room 33 | accessible boolean, // Accessibility status of the room 34 | image varchar(2000), // URL to the room's image 35 | description varchar(2000), // Description of the room 36 | features varchar(100) ARRAY, // Array of room features (TV, WiFi, etc.) 37 | roomPrice int, // Price of the room 38 | primary key (roomid) // Primary key on roomid 39 | ); 40 | """); 41 | } 42 | 43 | // Method to create a room entry in the ROOMS table 44 | public void createRoom() throws SQLException { 45 | Statement st = connection.createStatement(); 46 | 47 | // Insert a new room into the ROOMS table with predefined values 48 | st.executeUpdate(""" 49 | INSERT INTO ROOMS (room_name, type, beds, accessible, image, description, features, roomPrice) 50 | VALUES ( 51 | '101', // Room name or number 52 | 'single', // Room type (single room) 53 | 1, // Number of beds 54 | true, // Room is accessible 55 | '/images/room2.jpg', // URL of the room's image 56 | 'A generated description', // Room description 57 | ARRAY['TV', 'WiFi', 'Safe'], // Room features as an array 58 | 100); // Room price 59 | """); 60 | } 61 | 62 | // Method to create a booking entry in the BOOKINGS table for a given room 63 | public void createBooking(int roomid) throws SQLException { 64 | Statement st = connection.createStatement(); 65 | 66 | // Insert a new booking into the BOOKINGS table for a specific room ID 67 | st.executeUpdate(""" 68 | INSERT INTO BOOKINGS (roomid, firstname, lastname, depositpaid, checkin, checkout) 69 | VALUES ( 70 | ?, // Room ID (foreign key) 71 | 'James', // First name of the guest 72 | 'Dean', // Last name of the guest 73 | true, // Deposit is paid 74 | '2022-02-01', // Check-in date 75 | '2022-02-05' // Check-out date 76 | ); 77 | """.replace("?", Integer.toString(roomid))); // Replace '?' with the actual roomid value 78 | } 79 | 80 | // Method to output the results of a query to the console 81 | public void outputTables(String query) throws SQLException { 82 | Statement st = connection.createStatement(); 83 | 84 | // Execute the query and get the result set 85 | ResultSet rs = st.executeQuery(query); 86 | 87 | // Get metadata about the result set (such as column names and count) 88 | ResultSetMetaData rsmd = rs.getMetaData(); 89 | int columnsNumber = rsmd.getColumnCount(); 90 | 91 | // Loop through the result set and print each row of data 92 | while (rs.next()) { 93 | for(int i = 1 ; i <= columnsNumber; i++){ 94 | // Print each column value in the current row 95 | System.out.print(rs.getString(i) + " "); 96 | } 97 | // Move to a new line after each row 98 | System.out.println(); 99 | } 100 | } 101 | 102 | // Method to retrieve the most recently created room ID 103 | public int getRoomId() throws SQLException { 104 | Statement st = connection.createStatement(); 105 | 106 | // Execute a query to get the most recent room ID 107 | ResultSet rs = st.executeQuery("SELECT roomid FROM ROOMS ORDER BY roomid DESC"); 108 | 109 | // If a room exists, return its ID; otherwise, return 0 110 | if(rs.next()){ 111 | return rs.getInt("roomid"); 112 | } else { 113 | return 0; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /chapter-12/src/main/java/JavaParser.java: -------------------------------------------------------------------------------- 1 | import com.github.javaparser.StaticJavaParser; 2 | import com.github.javaparser.ast.CompilationUnit; 3 | import com.github.javaparser.ast.ImportDeclaration; 4 | import com.github.javaparser.ast.NodeList; 5 | import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; 6 | import com.github.javaparser.ast.body.MethodDeclaration; 7 | import com.github.javaparser.ast.expr.AnnotationExpr; 8 | import com.github.javaparser.ast.visitor.VoidVisitorAdapter; 9 | 10 | import java.io.FileInputStream; 11 | import java.io.FileNotFoundException; 12 | import java.io.IOException; 13 | import java.nio.file.Files; 14 | import java.nio.file.Path; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | public class JavaParser { 19 | 20 | private final List codeSnippets = new ArrayList<>(); 21 | private String importList = ""; 22 | private String filename = ""; 23 | 24 | public JavaParser(String rootPath) throws IOException { 25 | // Specify the directory containing your Java source files 26 | Path sourceDirectory = Path.of(rootPath); 27 | 28 | // Parse each Java file in the source directory 29 | Files.walk(sourceDirectory) 30 | .filter(path -> path.toString().endsWith(".java")) 31 | .forEach(path -> { 32 | System.out.println("Parsing " + path.getFileName() + "..."); 33 | CompilationUnit compilationUnit = null; 34 | filename = path.getFileName().toString().replace(".java", ""); 35 | 36 | try { 37 | compilationUnit = StaticJavaParser.parse(new FileInputStream(path.toString())); 38 | } catch (FileNotFoundException e) { 39 | throw new RuntimeException(e); 40 | } 41 | 42 | // Visit and print method names 43 | compilationUnit.accept(new PackageVisitor(), null); 44 | compilationUnit.accept(new ImportVisitor(), null); 45 | 46 | addEntry("What imports are being added to " + filename, importList); 47 | 48 | compilationUnit.accept(new ClassVisitor(), null); 49 | }); 50 | } 51 | 52 | public List getCodeSnippets() { 53 | return codeSnippets; 54 | } 55 | 56 | private class PackageVisitor extends VoidVisitorAdapter { 57 | @Override 58 | public void visit(CompilationUnit compilationUnit, Void arg) { 59 | if(compilationUnit.getPackageDeclaration().isPresent()){ 60 | addEntry("What package does " + filename + " belong to", "package " + compilationUnit.getPackageDeclaration().get().getName() + ";"); 61 | } 62 | 63 | super.visit(compilationUnit, arg); 64 | } 65 | } 66 | 67 | private class ImportVisitor extends VoidVisitorAdapter { 68 | @Override 69 | public void visit(ImportDeclaration importDeclaration, Void arg) { 70 | importList += "import " + importDeclaration.getNameAsString() + ";\n"; 71 | 72 | super.visit(importDeclaration, arg); 73 | } 74 | } 75 | 76 | private class ClassVisitor extends VoidVisitorAdapter { 77 | @Override 78 | public void visit(ClassOrInterfaceDeclaration classDeclaration, Void arg) { 79 | if(classDeclaration.getAnnotations().isEmpty()){ 80 | addEntry("What is the class declaration for " + filename, "public class " + classDeclaration.getName() + " {\n\n}"); 81 | } else { 82 | String annotationList = buildAnnotationList(classDeclaration.getAnnotations()); 83 | 84 | addEntry("What is the class declaration for " + filename, annotationList + "public class " + classDeclaration.getName() + " {\n\n}"); 85 | } 86 | 87 | 88 | classDeclaration.getFields().forEach(field -> { 89 | String methodAnnotations = buildAnnotationList(field.getAnnotations()); 90 | 91 | if(!field.getModifiers().isEmpty()) { 92 | if(field.getVariables().get(0).getInitializer().isPresent()) 93 | addEntry("What is the variable " + field.getVariables().get(0).getName() + " assigned to in " + filename + "?", methodAnnotations + field.getModifiers().get(0) + field.getElementType().asString() + " " + field.getVariables().get(0).getName() + " = " + field.getVariables().get(0).getInitializer().get() + ";"); 94 | else 95 | addEntry("List variables declared in " + filename, methodAnnotations + field.getModifiers().get(0) + field.getElementType().asString() + " " + field.getVariables().get(0).getName() + ";"); 96 | } 97 | }); 98 | 99 | // Visit and print details of each method 100 | classDeclaration.getMethods().forEach(method -> method.accept(new MethodVisitor(), null)); 101 | 102 | super.visit(classDeclaration, arg); 103 | } 104 | } 105 | 106 | private class MethodVisitor extends VoidVisitorAdapter { 107 | @Override 108 | public void visit(MethodDeclaration md, Void arg) { 109 | String annotations = buildAnnotationList(md.getAnnotations()); 110 | 111 | if(md.getBody().isPresent()) { 112 | addEntry("How does the method " + md.getName() + " work for " + filename + "?",annotations + md.getDeclarationAsString() + "\n" + md.getBody().get().toString()); 113 | } 114 | 115 | super.visit(md, arg); 116 | } 117 | } 118 | 119 | private void addEntry(String instruction, String entry){ 120 | codeSnippets.add(new JsonlEntry(instruction,entry)); 121 | } 122 | 123 | private String buildAnnotationList(NodeList annotations){ 124 | StringBuilder annotationList = new StringBuilder(); 125 | 126 | for(AnnotationExpr annotation : annotations){ 127 | annotationList.append("@").append(annotation.getName()).append("\n"); 128 | } 129 | 130 | return annotationList.toString(); 131 | } 132 | 133 | } 134 | --------------------------------------------------------------------------------