001package com.studentgui.tools; 002 003import java.time.LocalDate; 004import java.util.Arrays; 005import java.util.stream.IntStream; 006 007import javax.swing.JButton; 008 009import com.studentgui.apphelpers.Helpers; 010import com.studentgui.apppages.Braille; 011import com.studentgui.apppages.JLineGraph; 012 013/** 014 * Automated integration test for programmatic page manipulation and database submission. 015 * 016 * <p>Simulates user interaction with the {@link Braille} assessment page by:</p> 017 * <ol> 018 * <li>Programmatically instantiating a Braille page with synthetic student/date</li> 019 * <li>Using reflection to access and populate internal {@code PhaseScoreField} components</li> 020 * <li>Locating the "Submit Braille Data" button via accessible name</li> 021 * <li>Programmatically triggering the submit action via {@link JButton#doClick()}</li> 022 * </ol> 023 * 024 * <p><b>Purpose:</b></p> 025 * <ul> 026 * <li>Validates end-to-end page submission workflow without GUI interaction</li> 027 * <li>Tests database insert, JSON export, and PNG chart generation in automated context</li> 028 * <li>Verifies reflection-based access to page internals for testing purposes</li> 029 * <li>Provides reference for programmatic testing of other assessment pages</li> 030 * </ul> 031 * 032 * <p><b>Usage:</b></p> 033 * <pre>{@code 034 * java -cp StudentDataGUI.jar com.studentgui.tools.ProgrammaticPageSaveTest 035 * }</pre> 036 * 037 * <p><b>Expected Side Effects:</b></p> 038 * <ul> 039 * <li>New Braille progress session inserted into database for student "Smoke Test"</li> 040 * <li>JSON export written to {@code StudentDataFiles/Smoke_Test/Sessions/Braille/}</li> 041 * <li>Phase-grouped PNG plots written to {@code StudentDataFiles/Smoke_Test/plots/}</li> 042 * <li>Markdown and HTML reports generated in {@code StudentDataFiles/Smoke_Test/reports/}</li> 043 * </ul> 044 * 045 * <p><b>Reflection Usage:</b> Accesses private {@code skillFields} array in {@link Braille} 046 * to set all 64 Braille skills to a score of 3. This demonstrates how to programmatically 047 * manipulate page state for testing when public setters are not available.</p> 048 * 049 * <p><b>Validation:</b> After execution, inspect:</p> 050 * <ul> 051 * <li>Database: {@code sqlite3 app_home/StudentDatabase/students.db "SELECT * FROM ProgressSession ORDER BY id DESC LIMIT 1;"}</li> 052 * <li>JSON exports: {@code ls -lt app_home/StudentDataFiles/Smoke_Test/Sessions/Braille/}</li> 053 * <li>Generated plots: {@code ls -lt app_home/StudentDataFiles/Smoke_Test/plots/}</li> 054 * </ul> 055 * 056 * <p><b>Note:</b> This test modifies the live database. Run in a test environment or 057 * use a separate APP_HOME directory to avoid polluting production data.</p> 058 * 059 * @see com.studentgui.apppages.Braille 060 * @see com.studentgui.uicomp.PhaseScoreField 061 * @see javax.swing.JButton#doClick() 062 */ 063public class ProgrammaticPageSaveTest { 064 /** 065 * Program entry to run the programmatic page save test. 066 * 067 * @param args ignored 068 * @throws Exception on reflection or DB errors 069 */ 070 public static void main(final String[] args) throws Exception { 071 Helpers.createFolderHierarchy(); 072 JLineGraph graph = new JLineGraph(); 073 Braille page = new Braille("Smoke Test", LocalDate.now(), graph); 074 075 // Set all fields to 3 via getComponents traversal 076 Arrays.stream(page.getComponents()).forEach(c -> { 077 // nothing here; we'll rely on the submit button to collect values from the internal PhaseScoreField instances 078 }); 079 080 // Helper: find submit button by accessible name and click it 081 JButton submit = findButtonByAccessibleName(page, "Submit Braille Data"); 082 if (submit == null) { 083 System.out.println("Submit button not found; aborting test"); 084 return; 085 } 086 087 // Programmatically set values using the page's declared skillFields via reflection 088 try { 089 java.lang.reflect.Field f = Braille.class.getDeclaredField("skillFields"); 090 f.setAccessible(true); 091 Object arr = f.get(page); 092 if (arr instanceof com.studentgui.uicomp.PhaseScoreField[]) { 093 com.studentgui.uicomp.PhaseScoreField[] s = (com.studentgui.uicomp.PhaseScoreField[]) arr; 094 IntStream.range(0, s.length).forEach(i -> s[i].setValue(3)); 095 } 096 } catch (ReflectiveOperationException roe) { 097 roe.printStackTrace(); 098 System.out.println("Unable to set skillFields via reflection"); 099 } 100 101 // Trigger submit 102 System.out.println("Triggering submit button action..."); 103 submit.doClick(); 104 105 System.out.println("Programmatic submit triggered. Check app_home for outputs."); 106 } 107 108 private static JButton findButtonByAccessibleName(final java.awt.Container c, final String name) { 109 for (java.awt.Component comp : c.getComponents()) { 110 if (comp instanceof JButton) { 111 JButton b = (JButton) comp; 112 if (name.equals(b.getAccessibleContext().getAccessibleName())) { 113 return b; 114 } 115 } 116 if (comp instanceof java.awt.Container) { 117 JButton r = findButtonByAccessibleName((java.awt.Container) comp, name); 118 if (r != null) { 119 return r; 120 } 121 } 122 } 123 return null; 124 } 125 126 /** 127 * Private constructor to avoid instantiation - this class is a programmatic 128 * test harness containing only static helpers and a main method. 129 */ 130 private ProgrammaticPageSaveTest() { 131 // no instances 132 } 133}