1 module nodes.password_input; 2 3 import fluid; 4 5 @safe: 6 7 Theme testTheme; 8 9 static this() { 10 testTheme = nullTheme.derive( 11 rule!PasswordInput( 12 Rule.fontSize = 14.pt, 13 Rule.backgroundColor = color("#f0f"), 14 Rule.selectionBackgroundColor = color("#700"), 15 Rule.textColor = color("#000"), 16 ), 17 ); 18 } 19 20 @("PasswordInput draws background and contents") 21 unittest { 22 23 auto input = passwordInput(.testTheme); 24 auto root = testSpace(input); 25 26 root.drawAndAssert( 27 input.drawsRectangle(0, 0, 200, 27).ofColor("#ff00ff"), 28 input.cropsTo(0, 0, 200, 27), 29 input.resetsCrop(), 30 ); 31 input.value = "woo"; 32 root.drawAndAssert( 33 input.drawsRectangle(0, 0, 200, 27).ofColor("#ff00ff"), 34 input.cropsTo(0, 0, 200, 27), 35 input.drawsCircle().at( 5, 13.5).ofRadius(5).ofColor("#000000"), 36 input.drawsCircle().at(17, 13.5).ofRadius(5).ofColor("#000000"), 37 input.drawsCircle().at(29, 13.5).ofRadius(5).ofColor("#000000"), 38 input.resetsCrop(), 39 ); 40 41 } 42 43 @("PasswordInput scrolls when there is too much text to fit in its width") 44 unittest { 45 46 auto input = passwordInput(.testTheme); 47 auto root = testSpace(input); 48 49 input.value = "correct horse battery staple"; 50 root.draw(); 51 input.caretToEnd(); 52 53 root.drawAndAssert( 54 input.drawsRectangle(0, 0, 200, 27).ofColor("#ff00ff"), 55 input.cropsTo (0, 0, 200, 27), 56 // ... many irrelevant dots skipped... 57 input.drawsCircle().at(-23, 13.5).ofRadius(5).ofColor("#000000"), 58 input.drawsCircle().at(-11, 13.5).ofRadius(5).ofColor("#000000"), 59 input.drawsCircle().at( 1, 13.5).ofRadius(5).ofColor("#000000"), 60 input.drawsCircle().at( 13, 13.5).ofRadius(5).ofColor("#000000"), 61 // ... more dots skipped... 62 input.drawsCircle().at(181, 13.5).ofRadius(5).ofColor("#000000"), 63 input.drawsCircle().at(193, 13.5).ofRadius(5).ofColor("#000000"), 64 input.resetsCrop(), 65 ); 66 67 } 68 69 @("PasswordInput draws a rectangle behind selection") 70 unittest { 71 72 auto input = passwordInput(.testTheme); 73 auto root = testSpace(input); 74 75 input.value = "correct horse"; 76 root.draw(); 77 input.selectSlice("correct ".length, input.value.length); 78 79 root.drawAndAssert( 80 input.drawsRectangle(0, 0, 200, 27).ofColor("#ff00ff"), 81 input.cropsTo (0, 0, 200, 27), 82 input.drawsRectangle(96, 0, 60, 27).ofColor("#770000"), 83 input.drawsCircle().at( 5, 13.5).ofRadius(5).ofColor("#000000"), 84 input.drawsCircle().at( 17, 13.5).ofRadius(5).ofColor("#000000"), 85 // ... irrelevant dots skipped... 86 input.drawsCircle().at( 89, 13.5).ofRadius(5).ofColor("#000000"), // space 87 input.drawsCircle().at(101, 13.5).ofRadius(5).ofColor("#000000"), // h 88 input.drawsCircle().at(113, 13.5).ofRadius(5).ofColor("#000000"), // o 89 input.drawsCircle().at(125, 13.5).ofRadius(5).ofColor("#000000"), // r 90 input.drawsCircle().at(137, 13.5).ofRadius(5).ofColor("#000000"), // s 91 input.drawsCircle().at(149, 13.5).ofRadius(5).ofColor("#000000"), // e 92 ); 93 94 } 95 96 @("PasswordInput.shred fills data with invalid characters") 97 unittest { 98 99 auto root = passwordInput(); 100 root.value = "Hello, "; 101 root.caretToEnd(); 102 root.push("World!"); 103 104 assert(root.value == "Hello, World!"); 105 106 auto value1 = root.value; 107 root.shred(); 108 109 assert(root.value == ""); 110 assert(value1 == "Hello, \xFF\xFF\xFF\xFF\xFF\xFF"); 111 112 root.push("Hello, World!"); 113 root.runInputAction!(FluidInputAction.previousChar); 114 115 auto value2 = root.value; 116 root.chopWord(); 117 root.push("Fluid"); 118 119 auto value3 = root.value; 120 121 assert(root.value == "Hello, Fluid!"); 122 assert(value2 == "Hello, World!"); 123 assert(value3 == "Hello, Fluid!"); 124 125 root.shred(); 126 127 assert(root.value == ""); 128 assert(value2 == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); 129 assert(value3 == value2); 130 131 } 132 133 @("PasswordInput.shred clears edit history") 134 unittest { 135 136 auto root = passwordInput(); 137 root.push("Hello, x"); 138 root.chop(); 139 root.push("World!"); 140 141 assert(root.value == "Hello, World!"); 142 143 root.undo(); 144 145 assert(root.value == "Hello, "); 146 147 root.shred(); 148 149 assert(root.value == ""); 150 151 root.undo(); 152 153 assert(root.value == ""); 154 155 root.redo(); 156 root.redo(); 157 158 assert(root.value == ""); 159 160 } 161 162 @("PasswordInput correctly handles large inputs in HiDPI") 163 unittest { 164 165 enum textConstant = " one two three four"; 166 167 auto node = passwordInput(); 168 auto focus = focusChain(node); 169 auto root = testSpace(.testTheme, focus); 170 root.setScale(1.25); 171 focus.currentFocus = node; 172 173 node.push(textConstant); 174 root.draw(); 175 root.drawAndAssert( 176 node.cropsTo(0, 0, 200, 27), 177 node.drawsCircle().at(-7.84, 13.2).ofRadius(5.2).ofColor("#000000"), 178 node.drawsCircle().at(4.64, 13.2).ofRadius(5.2).ofColor("#000000"), 179 node.drawsCircle().at(17.12, 13.2).ofRadius(5.2).ofColor("#000000"), 180 // ... more circles... 181 node.drawsCircle().at(179.36, 13.2).ofRadius(5.2).ofColor("#000000"), 182 node.drawsCircle().at(191.84, 13.2).ofRadius(5.2).ofColor("#000000"), 183 node.drawsLine().from(199.12, 2.64).to(199.12, 23.76).ofWidth(1).ofColor("#000000"), 184 ); 185 186 node.push(textConstant); 187 root.drawAndAssert( 188 node.cropsTo(0, 0, 200, 27), 189 node.drawsCircle().at(-6.96003, 13.2).ofRadius(5.2).ofColor("#000000"), 190 node.drawsCircle().at(5.51997, 13.2).ofRadius(5.2).ofColor("#000000"), 191 node.drawsCircle().at(18, 13.2).ofRadius(5.2).ofColor("#000000"), 192 // ... more circles... 193 node.drawsCircle().at(180.24, 13.2).ofRadius(5.2).ofColor("#000000"), 194 node.drawsCircle().at(192.72, 13.2).ofRadius(5.2).ofColor("#000000"), 195 node.drawsLine().from(200, 2.64).to(200, 23.76).ofWidth(1).ofColor("#000000"), 196 ); 197 198 } 199 200 @("PasswordInput draws a placeholder when empty") 201 unittest { 202 203 auto node = passwordInput("Placeholder..."); 204 auto root = testSpace(.testTheme, node); 205 206 root.drawAndAssert( 207 node.contentLabel.drawsHintedImage().at(0, 0, 121, 27).ofColor("#ffffff") 208 .sha256("b842ed720b325d744e4efb138bc2609667cb6f0b8735375e9ab3f5cde72789c6"), 209 ); 210 root.drawAndAssertFailure( 211 node.drawsCircle(), 212 ); 213 214 node.value = "a"; 215 216 root.drawAndAssertFailure( 217 node.contentLabel.drawsHintedImage().at(0, 0, 121, 27).ofColor("#ffffff") 218 .sha256("b842ed720b325d744e4efb138bc2609667cb6f0b8735375e9ab3f5cde72789c6"), 219 ); 220 root.drawAndAssert( 221 node.drawsCircle(), 222 ); 223 224 }