Coverage for tests/test_turtlesc.py: 100%

783 statements  

« prev     ^ index     » next       coverage.py v7.7.0, created at 2025-03-18 22:46 -0400

1import pytest 

2from turtle import * 

3from turtlesc import * 

4from random import * 

5 

6seed(42) # Keep at 42 for reproducible tests (dependent on which tests are run and in what order, anyway) 

7tracer(10000, 0) 

8 

9def test_basic_sc_calls(): 

10 # Blanks are no-ops and fine: 

11 assert sc('') == 0 

12 assert sc('', '') == 0 

13 assert sc(' ') == 0 

14 assert sc(' ', ' ') == 0 

15 assert sc('f 1, ') == 1 

16 assert sc('f -1, ', '\n', ' ') == 1 

17 

18 # Invalid commands raise exceptions: 

19 with pytest.raises(TurtleShortcutException): 

20 sc('invalid') 

21 with pytest.raises(TurtleShortcutException): 

22 sc('f') 

23 with pytest.raises(TurtleShortcutException): 

24 sc('f 1 2') 

25 with pytest.raises(TurtleShortcutException): 

26 sc('f invalid') 

27 

28 assert sc('f 1, f -1') == 2 

29 

30def test_in_radians_mode(): 

31 radians() 

32 assert in_radians_mode() 

33 degrees() 

34 assert not in_radians_mode() 

35 

36 

37def test_in_degrees_mode(): 

38 degrees() 

39 assert in_degrees_mode() 

40 radians() 

41 assert not in_degrees_mode() 

42 degrees() # These tests always use degrees mode. 

43 

44 

45def test_forward(): 

46 turtle.reset() 

47 

48 for name in ('f', 'forward', 'F', 'FORWARD', 'fOrWaRd'): 

49 with pytest.raises(TurtleShortcutException): 

50 sc(f'{name}') # Missing argument 

51 with pytest.raises(TurtleShortcutException): 

52 sc(f'{name} 1 2') # Too many arguments 

53 with pytest.raises(TurtleShortcutException): 

54 sc(f'{name} invalid') # Invalid argument 

55 

56 assert sc(f'{name} 1') == 1 

57 assert pos() == (1, 0) 

58 assert sc(f'{name} -1') == 1 

59 assert pos() == (0, 0) 

60 assert sc(f'{name} 0') == 1 

61 assert pos() == (0, 0) 

62 assert sc(f'{name} 0.5') == 1 

63 assert pos() == (0.5, 0) 

64 assert sc(f'{name} -0.5') == 1 

65 assert pos() == (0, 0) 

66 

67 

68def test_backward(): 

69 turtle.reset() 

70 

71 for name in ('b', 'backward', 'B', 'BACKWARD', 'bAcKwArD'): 

72 with pytest.raises(TurtleShortcutException): 

73 sc(f'{name}') # Missing argument 

74 with pytest.raises(TurtleShortcutException): 

75 sc(f'{name} 1 2') # Too many arguments 

76 with pytest.raises(TurtleShortcutException): 

77 sc(f'{name} invalid') # Invalid argument 

78 

79 assert sc(f'{name} 1') == 1 

80 assert pos() == (-1, 0) 

81 assert sc(f'{name} -1') == 1 

82 assert pos() == (0, 0) 

83 assert sc(f'{name} 0') == 1 

84 assert pos() == (0, 0) 

85 assert sc(f'{name} 0.5') == 1 

86 assert pos() == (-0.5, 0) 

87 assert sc(f'{name} -0.5') == 1 

88 assert pos() == (0, 0) 

89 

90 

91def test_right(): 

92 turtle.reset() 

93 

94 for name in ('r', 'right', 'R', 'RIGHT', 'rIgHt'): 

95 with pytest.raises(TurtleShortcutException): 

96 sc(f'{name}') # Missing argument 

97 with pytest.raises(TurtleShortcutException): 

98 sc(f'{name} 1 2') # Too many arguments 

99 with pytest.raises(TurtleShortcutException): 

100 sc(f'{name} invalid') # Invalid argument 

101 

102 assert sc(f'{name} 1') == 1 

103 assert heading() == 359 

104 assert sc(f'{name} -1') == 1 

105 assert heading() == 0 

106 assert sc(f'{name} 0') == 1 

107 assert heading() == 0 

108 assert sc(f'{name} 0.5') == 1 

109 assert heading() == 359.5 

110 assert sc(f'{name} -0.5') == 1 

111 assert heading() == 0 

112 

113 

114def test_left(): 

115 turtle.reset() 

116 

117 for name in ('l', 'left', 'L', 'LEFT', 'lEfT'): 

118 with pytest.raises(TurtleShortcutException): 

119 sc(f'{name}') # Missing argument 

120 with pytest.raises(TurtleShortcutException): 

121 sc(f'{name} 1 2') # Too many arguments 

122 with pytest.raises(TurtleShortcutException): 

123 sc(f'{name} invalid') # Invalid argument 

124 

125 assert sc(f'{name} 1') == 1 

126 assert heading() == 1 

127 assert sc(f'{name} -1') == 1 

128 assert heading() == 0 

129 assert sc(f'{name} 0') == 1 

130 assert heading() == 0 

131 assert sc(f'{name} 0.5') == 1 

132 assert heading() == 0.5 

133 assert sc(f'{name} -0.5') == 1 

134 assert heading() == 0 

135 

136 

137def test_setheading(): 

138 for name in ('sh', 'setheading', 'SH', 'SETHEADING', 'sEtHeAdInG'): 

139 with pytest.raises(TurtleShortcutException): 

140 sc(f'{name}') # Missing argument 

141 with pytest.raises(TurtleShortcutException): 

142 sc(f'{name} 1 2') # Too many arguments 

143 with pytest.raises(TurtleShortcutException): 

144 sc(f'{name} invalid') # Invalid argument 

145 

146 assert sc(f'{name} 1') == 1 

147 assert heading() == 1 

148 assert sc(f'{name} 0') == 1 

149 assert heading() == 0 

150 assert sc(f'{name} 360') == 1 

151 assert heading() == 0 

152 assert sc(f'{name} 720') == 1 

153 assert heading() == 0 

154 assert sc(f'{name} -360') == 1 

155 assert heading() == 0 

156 

157 

158def test_home(): 

159 for name in ('h', 'home', 'H', 'HOME', 'hOmE'): 

160 with pytest.raises(TurtleShortcutException): 

161 sc(f'{name} 1') # Too many arguments 

162 

163 assert sc(f'{name}') == 1 

164 assert pos() == (0, 0) 

165 assert heading() == 0 

166 

167 

168def test_clear(): 

169 for name in ('c', 'clear', 'C', 'CLEAR', 'cLeAr'): 

170 with pytest.raises(TurtleShortcutException): 

171 sc(f'{name} 1') # Too many arguments 

172 

173 assert sc(f'{name}') == 1 

174 

175 

176def test_goto(): 

177 for name in ('g', 'goto', 'G', 'GOTO', 'gOtO'): 

178 with pytest.raises(TurtleShortcutException): 

179 sc(f'{name}') # Missing argument 

180 with pytest.raises(TurtleShortcutException): 

181 sc(f'{name} 1') # Missing second argument 

182 with pytest.raises(TurtleShortcutException): 

183 sc(f'{name} 1 2 3') # Too many arguments 

184 with pytest.raises(TurtleShortcutException): 

185 sc(f'{name} 1 invalid') 

186 with pytest.raises(TurtleShortcutException): 

187 sc(f'{name} invalid 2') 

188 

189 assert sc(f'{name} 1 2') == 1 

190 assert pos() == (1, 2) 

191 assert sc(f'{name} -3 -4') == 1 

192 assert pos() == (-3, -4) 

193 assert sc(f'{name} 0 0') == 1 

194 assert pos() == (0, 0) 

195 assert sc(f'{name} 0.5 0.5') == 1 

196 assert pos() == (0.5, 0.5) 

197 assert sc(f'{name} -0.5 -0.5') == 1 

198 assert pos() == (-0.5, -0.5) 

199 

200 

201def test_tele(): 

202 for name in ('tele', 'TELE', 'tElE', 'teleport', 'TELEPORT', 'tElEpOrT'): 

203 with pytest.raises(TurtleShortcutException): 

204 sc(f'{name}') # Missing argument 

205 with pytest.raises(TurtleShortcutException): 

206 sc(f'{name} 1') # Missing second argument 

207 with pytest.raises(TurtleShortcutException): 

208 sc(f'{name} 1 2 3') # Too many arguments 

209 with pytest.raises(TurtleShortcutException): 

210 sc(f'{name} 1 invalid') 

211 with pytest.raises(TurtleShortcutException): 

212 sc(f'{name} invalid 2') 

213 

214 assert sc(f'{name} 1 2') == 1 

215 assert pos() == (1, 2) 

216 assert sc(f'{name} -3 -4') == 1 

217 assert pos() == (-3, -4) 

218 assert sc(f'{name} 0 0') == 1 

219 assert pos() == (0, 0) 

220 assert sc(f'{name} 0.5 0.5') == 1 

221 assert pos() == (0.5, 0.5) 

222 assert sc(f'{name} -0.5 -0.5') == 1 

223 assert pos() == (-0.5, -0.5) 

224 

225 

226def test_setx(): 

227 for name in ('x', 'setx', 'X', 'SETX', 'sEtX'): 

228 reset() 

229 

230 with pytest.raises(TurtleShortcutException): 

231 sc(f'{name}') # Missing argument 

232 with pytest.raises(TurtleShortcutException): 

233 sc(f'{name} 1 2') # Too many arguments 

234 with pytest.raises(TurtleShortcutException): 

235 sc(f'{name} invalid') # Invalid argument 

236 

237 assert sc(f'{name} 1') == 1 

238 assert pos() == (1, 0) 

239 assert sc(f'{name} -2') == 1 

240 assert pos() == (-2, 0) 

241 assert sc(f'{name} 0.5') == 1 

242 assert pos() == (0.5, 0) 

243 assert sc(f'{name} -0.5') == 1 

244 assert pos() == (-0.5, 0) 

245 

246 sety(10) 

247 assert sc(f'{name} 1') == 1 

248 assert pos() == (1, 10) 

249 

250 

251def test_sety(): 

252 for name in ('y', 'sety', 'Y', 'SETY', 'sEtY'): 

253 reset() 

254 

255 with pytest.raises(TurtleShortcutException): 

256 sc(f'{name}') # Missing argument 

257 with pytest.raises(TurtleShortcutException): 

258 sc(f'{name} 1 2') # Too many arguments 

259 with pytest.raises(TurtleShortcutException): 

260 sc(f'{name} invalid') # Invalid argument 

261 

262 assert sc(f'{name} 1') == 1 

263 assert pos() == (0, 1) 

264 assert sc(f'{name} -2') == 1 

265 assert pos() == (0, -2) 

266 assert sc(f'{name} 0.5') == 1 

267 assert pos() == (0, 0.5) 

268 assert sc(f'{name} -0.5') == 1 

269 assert pos() == (0, -0.5) 

270 

271 setx(10) 

272 assert sc(f'{name} 1') == 1 

273 assert pos() == (10, 1) 

274 

275 

276 

277def test_pendown(): 

278 for name in ('pd', 'pendown', 'PD', 'PENDOWN', 'pEnDoWn'): 

279 with pytest.raises(TurtleShortcutException): 

280 sc(f'{name} 1') # Too many arguments 

281 

282 penup() 

283 assert sc(f'{name}') == 1 

284 assert isdown() 

285 

286 

287def test_penup(): 

288 for name in ('pu', 'penup', 'PU', 'PENUP', 'pEnUp'): 

289 with pytest.raises(TurtleShortcutException): 

290 sc(f'{name} 1') # Too many arguments 

291 

292 pendown() 

293 assert sc(f'{name}') == 1 

294 assert not isdown() 

295 

296 

297def test_pensize(): 

298 for name in ('ps', 'pensize', 'PS', 'PENSIZE', 'pEnSiZe'): 

299 with pytest.raises(TurtleShortcutException): 

300 sc(f'{name}') # Missing argument 

301 with pytest.raises(TurtleShortcutException): 

302 sc(f'{name} 1 2') # Too many arguments 

303 with pytest.raises(TurtleShortcutException): 

304 sc(f'{name} invalid') # Invalid argument 

305 

306 assert sc(f'{name} 10') == 1 

307 assert pensize() == 10 

308 

309 assert sc(f'{name} 1.5') == 1 

310 assert pensize() == 1.5 

311 

312 pensize(1) 

313 

314 

315def test_stamp(): 

316 for name in ('st', 'stamp', 'ST', 'STAMP', 'sTaMp'): 

317 reset() 

318 

319 with pytest.raises(TurtleShortcutException): 

320 sc(f'{name} 1') # Too many arguments 

321 

322 assert sc(f'{name}') == 1 

323 

324 

325def test_pencolor(): 

326 for name in ('pc', 'pencolor', 'PC', 'PENCOLOR', 'pEnCoLoR'): 

327 with pytest.raises(TurtleShortcutException): 

328 sc(f'{name}') # Missing argument 

329 

330 with pytest.raises(TurtleShortcutException): 

331 sc(f'{name} 1 2') # Missing argument 

332 

333 with pytest.raises(TurtleShortcutException): 

334 sc(f'{name} invalid 0 0') # Invalid argument 

335 with pytest.raises(TurtleShortcutException): 

336 sc(f'{name} 0 invalid 0') # Invalid argument 

337 with pytest.raises(TurtleShortcutException): 

338 sc(f'{name} 0 0 invalid') # Invalid argument 

339 

340 

341 colormode(1.0) # Set to 1.0 for testing 

342 

343 pencolor('black') # Reset to black 

344 assert sc(f'{name} red') == 1 

345 assert pencolor() == 'red' 

346 

347 pencolor('black') # Reset to black 

348 assert sc(f'{name} red') == 1 

349 assert pencolor() == 'red' 

350 

351 pencolor('black') # Reset to black 

352 assert sc(f'{name} 1 0 0') == 1 

353 assert pencolor() == (1.0, 0.0, 0.0) 

354 

355 pencolor('black') # Reset to black 

356 assert sc(f'{name} 1.0 0.0 0.0') == 1 

357 assert pencolor() == (1.0, 0.0, 0.0) 

358 

359 pencolor('black') # Reset to black 

360 assert sc(f'{name} 255 0 0') == 1 # Test that temporarily setting colormode to 255 works. 

361 assert pencolor() == (1.0, 0.0, 0.0) 

362 

363 colormode(255) # Test that temporarily setting colormode to 1 works. 

364 assert sc(f'{name} 0 1.0 0') == 1 

365 colormode(1.0) 

366 assert pencolor() == (0, 1, 0) 

367 

368 for color_name in 'black blue brown orange gray grey green purple violet pink yellow white red magenta cyan'.split(): 

369 assert sc(f'{name} {color_name}') == 1 

370 assert pencolor() == color_name 

371 

372 colormode(255) 

373 assert sc(f'{name} FF0000') == 1 

374 assert pencolor() == (255, 0, 0.0) 

375 

376 colormode(1) 

377 assert sc(f'{name} FF0000') == 1 

378 assert pencolor() == (1, 0, 0.0) 

379 

380 with pytest.raises(TurtleShortcutException): 

381 sc(f'{name} xxyyzz') # Invalid color name 

382 

383 

384def test_fillcolor(): 

385 for name in ('fc', 'fillcolor', 'FC', 'FILLCOLOR', 'fIlLcOlOr'): 

386 with pytest.raises(TurtleShortcutException): 

387 sc(f'{name}') # Missing argument 

388 

389 with pytest.raises(TurtleShortcutException): 

390 sc(f'{name} 1 2') # Missing argument 

391 

392 with pytest.raises(TurtleShortcutException): 

393 sc(f'{name} invalid 0 0') # Invalid argument 

394 with pytest.raises(TurtleShortcutException): 

395 sc(f'{name} 0 invalid 0') # Invalid argument 

396 with pytest.raises(TurtleShortcutException): 

397 sc(f'{name} 0 0 invalid') # Invalid argument 

398 

399 

400 colormode(1.0) # Set to 1.0 for testing 

401 

402 fillcolor('black') # Reset to black 

403 assert sc(f'{name} red') == 1 

404 assert fillcolor() == 'red' 

405 

406 fillcolor('black') # Reset to black 

407 assert sc(f'{name} red') == 1 

408 assert fillcolor() == 'red' 

409 

410 fillcolor('black') # Reset to black 

411 assert sc(f'{name} 1 0 0') == 1 

412 assert fillcolor() == (1.0, 0.0, 0.0) 

413 

414 fillcolor('black') # Reset to black 

415 assert sc(f'{name} 1.0 0.0 0.0') == 1 

416 assert fillcolor() == (1.0, 0.0, 0.0) 

417 

418 pencolor('black') # Reset to black 

419 assert sc(f'{name} 255 0 0') == 1 # Test that temporarily setting colormode to 255 works. 

420 assert fillcolor() == (1.0, 0.0, 0.0) 

421 

422 colormode(255) # Test that temporarily setting colormode to 1 works. 

423 assert sc(f'{name} 0 1.0 0') == 1 

424 colormode(1.0) 

425 assert fillcolor() == (0, 1, 0) 

426 

427 for color_name in 'black blue brown orange gray grey green purple violet pink yellow white red magenta cyan'.split(): 

428 assert sc(f'{name} {color_name}') == 1 

429 assert fillcolor() == color_name 

430 

431 colormode(255) 

432 assert sc(f'{name} FF0000') == 1 

433 assert fillcolor() == (255, 0, 0.0) 

434 

435 with pytest.raises(TurtleShortcutException): 

436 sc(f'{name} xxyyzz') # Invalid color name 

437 

438 

439def test_bgcolor(): 

440 for name in ('bc', 'bgcolor', 'BC', 'BGCOLOR', 'bGcOlOr'): 

441 with pytest.raises(TurtleShortcutException): 

442 sc(f'{name}') # Missing argument 

443 

444 with pytest.raises(TurtleShortcutException): 

445 sc(f'{name} 1 2') # Missing argument 

446 

447 with pytest.raises(TurtleShortcutException): 

448 sc(f'{name} invalid 0 0') # Invalid argument 

449 with pytest.raises(TurtleShortcutException): 

450 sc(f'{name} 0 invalid 0') # Invalid argument 

451 with pytest.raises(TurtleShortcutException): 

452 sc(f'{name} 0 0 invalid') # Invalid argument 

453 

454 

455 colormode(1.0) # Set to 1.0 for testing 

456 

457 bgcolor('black') # Reset to black 

458 assert sc(f'{name} red') == 1 

459 assert bgcolor() == 'red' 

460 

461 bgcolor('black') # Reset to black 

462 assert sc(f'{name} red') == 1 

463 assert bgcolor() == 'red' 

464 

465 bgcolor('black') # Reset to black 

466 assert sc(f'{name} 1 0 0') == 1 

467 assert bgcolor() == (1.0, 0.0, 0.0) 

468 

469 bgcolor('black') # Reset to black 

470 assert sc(f'{name} 1.0 0.0 0.0') == 1 

471 assert bgcolor() == (1.0, 0.0, 0.0) 

472 

473 bgcolor('black') # Reset to black 

474 assert sc(f'{name} 255 0 0') == 1 # Test that temporarily setting colormode to 255 works. 

475 assert bgcolor() == (1.0, 0.0, 0.0) 

476 

477 colormode(255) # Test that temporarily setting colormode to 1 works. 

478 assert sc(f'{name} 0 1.0 0') == 1 

479 colormode(1.0) 

480 assert bgcolor() == (0, 1, 0) 

481 

482 for color_name in 'black blue brown orange gray grey green purple violet pink yellow white red magenta cyan'.split(): 

483 assert sc(f'{name} {color_name}') == 1 

484 assert bgcolor() == color_name 

485 

486 colormode(255) 

487 assert sc(f'{name} FF0000') == 1 

488 assert bgcolor() == (255, 0, 0.0) 

489 

490 with pytest.raises(TurtleShortcutException): 

491 sc(f'{name} xxyyzz') # Invalid color name 

492 

493 

494def test_circle(): 

495 for name in ('cir', 'circle', 'CIR', 'CIRCLE', 'cIrClE'): 

496 reset() 

497 

498 with pytest.raises(TurtleShortcutException): 

499 sc(f'{name}') # Missing argument 

500 with pytest.raises(TurtleShortcutException): 

501 sc(f'{name} 1 2') # Too many arguments 

502 with pytest.raises(TurtleShortcutException): 

503 sc(f'{name} invalid') # Invalid argument 

504 

505 # The (int(pos()[0]), int(pos()[1])) stuff is because Vec2D objects  

506 # returned from pos() consider (-0.00, -0.00) as not equal to (0, 0). 

507 

508 assert sc(f'{name} 1') == 1 

509 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

510 

511 assert sc(f'{name} 10') == 1 

512 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

513 

514 assert sc(f'{name} 10.5') == 1 

515 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

516 

517 assert sc(f'{name} -1') == 1 

518 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

519 

520 assert sc(f'{name} -10') == 1 

521 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

522 

523 assert sc(f'{name} -10.5') == 1 

524 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

525 

526 assert sc(f'{name} 0') == 1 

527 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

528 

529 

530def test_undo(): 

531 for name in ('undo', 'UNDO', 'uNdO'): 

532 reset() 

533 

534 with pytest.raises(TurtleShortcutException): 

535 sc(f'{name} 1') # Too many arguments 

536 

537 assert sc(f'{name}') == 1 

538 

539 

540def test_begin_fill_end(): 

541 for name in ('bf', 'begin_fill', 'BF', 'BEGIN_FILL', 'bEgIn_FiLl'): 

542 with pytest.raises(TurtleShortcutException): 

543 sc(f'{name} 1') # Too many arguments 

544 

545 assert sc(f'{name}') == 1 

546 end_fill() 

547 

548 

549def test_end_fill(): 

550 for name in ('ef', 'end_fill', 'EF', 'END_FILL', 'eNd_FiLl'): 

551 with pytest.raises(TurtleShortcutException): 

552 sc(f'{name} 1') # Too many arguments 

553 

554 begin_fill() 

555 assert sc(f'{name}') == 1 

556 

557 

558def test_reset(): 

559 for name in ('reset', 'RESET', 'rEsEt'): 

560 with pytest.raises(TurtleShortcutException): 

561 sc(f'{name} 1') # Too many arguments 

562 

563 assert sc(f'{name}') == 1 

564 

565 

566def test_sleep_sc(): 

567 for name in ('sleep', 'SLEEP', 'sLeEp'): 

568 with pytest.raises(TurtleShortcutException): 

569 sc(f'{name}') 

570 

571 

572 

573 

574def test_move_turn(): 

575 # Test the move and turn commands: 

576 

577 # Test home/h: 

578 goto(1, 0) 

579 assert sc('h') == 1 

580 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

581 

582 goto(1, 0) 

583 assert sc('home') == 1 

584 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

585 

586 with pytest.raises(TurtleShortcutException): 

587 sc('h 1') 

588 

589 # Test f/b forward/backward l/r left/right: 

590 assert sc('f 1') == 1 

591 assert (int(pos()[0]), int(pos()[1])) == (1, 0) 

592 

593 assert sc('forward 1') == 1 

594 assert (int(pos()[0]), int(pos()[1])) == (2, 0) 

595 

596 assert sc('b 1') == 1 

597 assert (int(pos()[0]), int(pos()[1])) == (1, 0) 

598 

599 assert sc('backward 1') == 1 

600 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

601 

602 assert sc('l 90') == 1 

603 assert heading() == 90 

604 

605 assert sc('left 90') == 1 

606 assert heading() == 180 

607 

608 assert sc('r 90') == 1 

609 assert heading() == 90 

610 

611 assert sc('right 90') == 1 

612 assert heading() == 0 

613 

614 assert sc('sh 42') == 1 

615 assert heading() == 42 

616 assert sc('sh 0') == 1 

617 assert heading() == 0 

618 

619 assert sc('f -1') == 1 

620 assert (int(pos()[0]), int(pos()[1])) == (-1, 0) 

621 

622 assert sc('b -1') == 1 

623 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

624 

625 assert sc('l -90') == 1 

626 assert heading() == 270 

627 

628 assert sc('r -90') == 1 

629 assert heading() == 0 

630 

631 assert sc('r 0') == 1 

632 assert heading() == 0 

633 

634 assert sc('r 360') == 1 

635 assert heading() == 0 

636 

637 assert sc('r 720') == 1 

638 assert heading() == 0 

639 

640 assert sc('r -360') == 1 

641 assert heading() == 0 

642 

643 assert sc('r -720') == 1 

644 assert heading() == 0 

645 

646 assert sc('l 0') == 1 

647 assert heading() == 0 

648 

649 assert sc('l 360') == 1 

650 assert heading() == 0 

651 

652 assert sc('l 720') == 1 

653 assert heading() == 0 

654 

655 assert sc('l -360') == 1 

656 assert heading() == 0 

657 

658 assert sc('l -720') == 1 

659 assert heading() == 0 

660 

661 assert sc('c') == 1 

662 assert sc('clear') == 1 

663 

664 # Test g and goto: 

665 assert sc('g 10 20') == 1 

666 assert (int(pos()[0]), int(pos()[1])) == (10, 20) 

667 

668 assert sc('goto -30 -40') == 1 

669 assert (int(pos()[0]), int(pos()[1])) == (-30, -40) 

670 

671 with pytest.raises(TurtleShortcutException): 

672 sc('goto 10') 

673 

674 with pytest.raises(TurtleShortcutException): 

675 sc('goto 10 invalid') 

676 

677 with pytest.raises(TurtleShortcutException): 

678 sc('goto invalid 20') 

679 

680 with pytest.raises(TurtleShortcutException): 

681 sc('goto invalid invalid') 

682 

683 with pytest.raises(TurtleShortcutException): 

684 sc('g') 

685 

686 assert sc('x 100') == 1 

687 assert (int(pos()[0]), int(pos()[1])) == (100, -40) 

688 

689 assert sc('y 200') == 1 

690 assert (int(pos()[0]), int(pos()[1])) == (100, 200) 

691 

692 assert sc('setx 300') == 1 

693 assert (int(pos()[0]), int(pos()[1])) == (300, 200) 

694 

695 assert sc('sety 400') == 1 

696 assert (int(pos()[0]), int(pos()[1])) == (300, 400) 

697 

698 with pytest.raises(TurtleShortcutException): 

699 sc('setx invalid') 

700 

701 with pytest.raises(TurtleShortcutException): 

702 sc('sety invalid') 

703 

704 with pytest.raises(TurtleShortcutException): 

705 sc('x invalid') 

706 

707 with pytest.raises(TurtleShortcutException): 

708 sc('y invalid') 

709 

710def test_cardinal_directions_nsew(): 

711 # Test calling a function while in radians mode: 

712 reset() 

713 radians() 

714 assert sc(f'n 100') == 1 

715 assert (int(pos()[0]), int(pos()[1])) == (0, 100) 

716 degrees() 

717 

718 for n, s, e, w, nw, ne, sw, se in ('n s e w nw ne sw se'.split(), 

719 'north south east west northwest northeast southwest southeast'.split(), 

720 'N S E W NW NE SW SE'.split(), 

721 'NORTH SOUTH EAST WEST NORTHWEST NORTHEAST SOUTHWEST SOUTHEAST'.split()): 

722 reset() 

723 assert sc(f'{n} 100') == 1 

724 assert (int(pos()[0]), int(pos()[1])) == (0, 100) 

725 assert sc(f'{n} -100') == 1 

726 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

727 

728 reset() 

729 assert sc(f'{s} 100') == 1 

730 assert (int(pos()[0]), int(pos()[1])) == (0, -100) 

731 assert sc(f'{s} -100') == 1 

732 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

733 

734 reset() 

735 assert sc(f'{e} 100') == 1 

736 assert (int(pos()[0]), int(pos()[1])) == (100, 0) 

737 assert sc(f'{e} -100') == 1 

738 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

739 

740 reset() 

741 assert sc(f'{w} 100') == 1 

742 assert (int(pos()[0]), int(pos()[1])) == (-100, 0) 

743 assert sc(f'{w} -100') == 1 

744 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

745 

746 reset() 

747 assert sc(f'{nw} 100') == 1 

748 assert (int(pos()[0]), int(pos()[1])) == (-70, 70) 

749 assert sc(f'{nw} -100') == 1 

750 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

751 

752 reset() 

753 assert sc(f'{ne} 100') == 1 

754 assert (int(pos()[0]), int(pos()[1])) == (70, 70) 

755 assert sc(f'{ne} -100') == 1 

756 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

757 

758 reset() 

759 assert sc(f'{sw} 100') == 1 

760 assert (int(pos()[0]), int(pos()[1])) == (-70, -70) 

761 assert sc(f'{sw} -100') == 1 

762 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

763 

764 reset() 

765 assert sc(f'{se} 100') == 1 

766 assert (int(pos()[0]), int(pos()[1])) == (70, -70) 

767 assert sc(f'{se} -100') == 1 

768 assert (int(pos()[0]), int(pos()[1])) == (0, 0) 

769 

770 

771def test_sleep(): 

772 with pytest.raises(TurtleShortcutException): 

773 sc('sleep') # Missing argument 

774 with pytest.raises(TurtleShortcutException): 

775 sc('sleep 1 2') # Too many arguments 

776 with pytest.raises(TurtleShortcutException): 

777 sc('sleep invalid') # Invalid argument 

778 

779 assert sc('sleep 1') == 1 

780 assert sc('sleep 0.1') == 1 

781 

782def test_tracer_update(): 

783 orig_tracer = tracer() 

784 orig_delay = delay() 

785 

786 for name in ('t', 'T', 'tracer', 'TRACER', 'tRaCeR'): 

787 with pytest.raises(TurtleShortcutException): 

788 sc('{name}') # Missing argument 

789 with pytest.raises(TurtleShortcutException): 

790 sc('{name} 1 2 3') # Too many arguments 

791 with pytest.raises(TurtleShortcutException): 

792 sc('{name} invalid 0') 

793 with pytest.raises(TurtleShortcutException): 

794 sc('{name} 0 invalid') 

795 

796 assert sc(f'{name} 123 1') == 1 

797 assert tracer() == 123 

798 assert delay() == 1 

799 

800 for name in ('u', 'U', 'update', 'UPDATE', 'uPdAtE'): 

801 with pytest.raises(TurtleShortcutException): 

802 sc('{name} 1') # Too many arguments 

803 

804 assert sc(f'{name}') == 1 

805 

806 tracer(orig_tracer, orig_delay) 

807 

808 

809def test_show_hide(): 

810 for name in ('show', 'SHOW', 'sHoW'): 

811 with pytest.raises(TurtleShortcutException): 

812 sc(f'{name} 1') # Too many arguments 

813 

814 assert sc(f'{name}') == 1 

815 assert isvisible() 

816 

817 for name in ('hide', 'HIDE', 'hIdE'): 

818 with pytest.raises(TurtleShortcutException): 

819 sc(f'{name} 1') # Too many arguments 

820 

821 assert sc(f'{name}') == 1 

822 assert not isvisible() 

823 

824 

825def test_dot(): 

826 for name in ('dot', 'DOT', 'dOt'): 

827 with pytest.raises(TurtleShortcutException): 

828 sc(f'{name}') # Missing argument 

829 with pytest.raises(TurtleShortcutException): 

830 sc(f'{name} 1 2') # Too many arguments 

831 with pytest.raises(TurtleShortcutException): 

832 sc(f'{name} invalid') # Invalid argument 

833 with pytest.raises(TurtleShortcutException): 

834 sc(f'{name} -1') # Invalid argument 

835 

836 

837 assert sc(f'{name} 1') == 1 

838 assert sc(f'{name} 10') == 1 

839 assert sc(f'{name} 10.5') == 1 

840 assert sc(f'{name} 0') == 1 

841 

842 

843def test_clearstamp(): 

844 for name in ('cs', 'clearstamp', 'CS', 'CLEARSTAMP', 'cLeArStAmP'): 

845 with pytest.raises(TurtleShortcutException): 

846 sc(f'{name} 1 2') # Too many arguments 

847 with pytest.raises(TurtleShortcutException): 

848 sc(f'{name}') # Missing argument 

849 with pytest.raises(TurtleShortcutException): 

850 sc(f'{name} invalid') # Invalid argument 

851 

852 stamp_id = stamp() 

853 assert sc(f'{name} {stamp_id}') == 1 

854 

855 

856def test_clearstamps(): 

857 for name in ('css', 'clearstamps', 'CSS', 'CLEARSTAMPS', 'cLeArStAmPs'): 

858 with pytest.raises(TurtleShortcutException): 

859 sc(f'{name} 1 2') # Too many arguments 

860 with pytest.raises(TurtleShortcutException): 

861 sc(f'{name} invalid') # Invalid argument 

862 

863 assert sc(f'{name} 0') == 1 

864 assert sc(f'{name} 2') == 1 

865 assert sc(f'{name} -2') == 1 

866 assert sc(f'{name}') == 1 

867 

868def test_speed(): 

869 for name in ('speed', 'SPEED', 'sPeEd'): 

870 with pytest.raises(TurtleShortcutException): 

871 sc(f'{name}') # Missing argument 

872 with pytest.raises(TurtleShortcutException): 

873 sc(f'{name} 1 2') # Too many arguments 

874 with pytest.raises(TurtleShortcutException): 

875 sc(f'{name} invalid') # Invalid argument 

876 

877 # Test numeric settings 0 to 10: 

878 for speed_setting in tuple(range(11)): 

879 assert sc(f'{name} {speed_setting}') == 1 

880 assert speed() == speed_setting 

881 # Test string settings: 

882 for speed_setting, numeric_equivalent in {'fastest': 0, 'fast': 10, 'normal': 6, 'slow': 3, 'slowest': 1, 'FASTEST': 0, 'FAST': 10, 'NORMAL': 6, 'SLOW': 3, 'SLOWEST': 1}.items(): 

883 assert sc(f'{name} {speed_setting}') == 1 

884 assert speed() == numeric_equivalent 

885 

886 tracer(10000, 0) # Restore the original tracer settings for other tests. 

887 

888 

889def test_get_turtle_code(): 

890 assert get_turtle_code('f 100') == ('forward(100)',) 

891 assert get_turtle_code('b 100') == ('backward(100)',) 

892 assert get_turtle_code('l 90') == ('left(90)',) 

893 assert get_turtle_code('r 90') == ('right(90)',) 

894 assert get_turtle_code('g 100 200') == ('goto(100, 200)',) 

895 assert get_turtle_code('sh 90') == ('setheading(90)',) 

896 assert get_turtle_code('pu') == ('penup()',) 

897 assert get_turtle_code('pd') == ('pendown()',) 

898 assert get_turtle_code('ps 10') == ('pensize(10)',) 

899 assert get_turtle_code('bf') == ('begin_fill()',) 

900 assert get_turtle_code('ef') == ('end_fill()',) 

901 assert get_turtle_code('reset') == ('reset()',) 

902 assert get_turtle_code('sleep 1') == ('sleep(1)',) 

903 assert get_turtle_code('t 100 0') == ('tracer(100, 0)',) 

904 assert get_turtle_code('u') == ('update()',) 

905 assert get_turtle_code('show') == ('showturtle()',) 

906 assert get_turtle_code('hide') == ('hideturtle()',) 

907 assert get_turtle_code('dot 10') == ('dot(10)',) 

908 assert get_turtle_code('cs 1') == ('clearstamp(1)',) 

909 assert get_turtle_code('css') == ('clearstamps()',) 

910 assert get_turtle_code('css 1') == ('clearstamps(1)',) 

911 assert get_turtle_code('st') == ('stamp()',) 

912 assert get_turtle_code('speed 1') == ('speed(1)',) 

913 assert get_turtle_code('home') == ('home()',) 

914 assert get_turtle_code('x 100') == ('setx(100)',) 

915 assert get_turtle_code('y 100') == ('sety(100)',) 

916 assert get_turtle_code('setx 100') == ('setx(100)',) 

917 assert get_turtle_code('sety 100') == ('sety(100)',) 

918 assert get_turtle_code('c') == ('clear()',) 

919 assert get_turtle_code('undo') == ('undo()',) 

920 assert get_turtle_code('cir 100') == ('circle(100)',) 

921 assert get_turtle_code('g 100 200') == ('goto(100, 200)',) 

922 assert get_turtle_code('tele 100 200') == ('teleport(100, 200)',) 

923 

924 assert get_turtle_code('pc red') == ("pencolor('red')",) 

925 assert get_turtle_code('fc red') == ("fillcolor('red')",) 

926 assert get_turtle_code('bc red') == ("bgcolor('red')",) 

927 

928 colormode(255) 

929 assert get_turtle_code('pc red') == ("pencolor('red')",) 

930 assert get_turtle_code('pc 255 0 0') == ('pencolor((255.0, 0.0, 0.0))',) 

931 assert get_turtle_code('fc 255 0 0') == ('fillcolor((255.0, 0.0, 0.0))',) 

932 assert get_turtle_code('bc 255 0 0') == ('bgcolor((255.0, 0.0, 0.0))',) 

933 

934 assert get_turtle_code('pc 1.0 0.0 0.0') == ('colormode(1.0)', 'pencolor((1.0, 0.0, 0.0))', 'colormode(255)') 

935 assert get_turtle_code('fc 1.0 0.0 0.0') == ('colormode(1.0)', 'fillcolor((1.0, 0.0, 0.0))', 'colormode(255)') 

936 assert get_turtle_code('bc 1.0 0.0 0.0') == ('colormode(1.0)', 'bgcolor((1.0, 0.0, 0.0))', 'colormode(255)') 

937 

938 colormode(1.0) 

939 assert get_turtle_code('pc red') == ("pencolor('red')",) 

940 assert get_turtle_code('pc 255 0 0') == ('colormode(255)', 'pencolor((255, 0, 0))', 'colormode(1.0)') 

941 assert get_turtle_code('fc 255 0 0') == ('colormode(255)', 'fillcolor((255, 0, 0))', 'colormode(1.0)') 

942 assert get_turtle_code('bc 255 0 0') == ('colormode(255)', 'bgcolor((255, 0, 0))', 'colormode(1.0)') 

943 

944 assert get_turtle_code('pc 1.0 0.0 0.0') == ('pencolor((1.0, 0.0, 0.0))',) 

945 assert get_turtle_code('fc 1.0 0.0 0.0') == ('fillcolor((1.0, 0.0, 0.0))',) 

946 assert get_turtle_code('bc 1.0 0.0 0.0') == ('bgcolor((1.0, 0.0, 0.0))',) 

947 

948 

949 

950 degrees() 

951 assert get_turtle_code('n 100') == ('setheading(90)', 'forward(100)') 

952 assert get_turtle_code('s 100') == ('setheading(270)', 'forward(100)') 

953 assert get_turtle_code('e 100') == ('setheading(0)', 'forward(100)') 

954 assert get_turtle_code('w 100') == ('setheading(180)', 'forward(100)') 

955 assert get_turtle_code('nw 100') == ('setheading(135)', 'forward(100)') 

956 assert get_turtle_code('ne 100') == ('setheading(45)', 'forward(100)') 

957 assert get_turtle_code('sw 100') == ('setheading(225)', 'forward(100)') 

958 assert get_turtle_code('se 100') == ('setheading(315)', 'forward(100)') 

959 assert get_turtle_code('north 100') == ('setheading(90)', 'forward(100)') 

960 assert get_turtle_code('south 100') == ('setheading(270)', 'forward(100)') 

961 assert get_turtle_code('east 100') == ('setheading(0)', 'forward(100)') 

962 assert get_turtle_code('west 100') == ('setheading(180)', 'forward(100)') 

963 assert get_turtle_code('northwest 100') == ('setheading(135)', 'forward(100)') 

964 assert get_turtle_code('northeast 100') == ('setheading(45)', 'forward(100)') 

965 assert get_turtle_code('southwest 100') == ('setheading(225)', 'forward(100)') 

966 assert get_turtle_code('southeast 100') == ('setheading(315)', 'forward(100)') 

967 assert get_turtle_code('N 100') == ('setheading(90)', 'forward(100)') 

968 assert get_turtle_code('S 100') == ('setheading(270)', 'forward(100)') 

969 assert get_turtle_code('E 100') == ('setheading(0)', 'forward(100)') 

970 assert get_turtle_code('W 100') == ('setheading(180)', 'forward(100)') 

971 assert get_turtle_code('NW 100') == ('setheading(135)', 'forward(100)') 

972 assert get_turtle_code('NE 100') == ('setheading(45)', 'forward(100)') 

973 assert get_turtle_code('SW 100') == ('setheading(225)', 'forward(100)') 

974 assert get_turtle_code('SE 100') == ('setheading(315)', 'forward(100)') 

975 assert get_turtle_code('NORTH 100') == ('setheading(90)', 'forward(100)') 

976 assert get_turtle_code('SOUTH 100') == ('setheading(270)', 'forward(100)') 

977 assert get_turtle_code('EAST 100') == ('setheading(0)', 'forward(100)') 

978 assert get_turtle_code('WEST 100') == ('setheading(180)', 'forward(100)') 

979 assert get_turtle_code('NORTHWEST 100') == ('setheading(135)', 'forward(100)') 

980 assert get_turtle_code('NORTHEAST 100') == ('setheading(45)', 'forward(100)') 

981 assert get_turtle_code('SOUTHWEST 100') == ('setheading(225)', 'forward(100)') 

982 assert get_turtle_code('SOUTHEAST 100') == ('setheading(315)', 'forward(100)') 

983 assert get_turtle_code('n 100, f 100') == ('setheading(90)', 'forward(100)', 'forward(100)') 

984 assert get_turtle_code('n 100, f 100, f 100') == ('setheading(90)', 'forward(100)', 'forward(100)', 'forward(100)') 

985 

986 radians() 

987 assert get_turtle_code('n 100') == ('degrees()', 'setheading(90)', 'forward(100)', 'radians()') 

988 assert get_turtle_code('s 100') == ('degrees()', 'setheading(270)', 'forward(100)', 'radians()') 

989 assert get_turtle_code('e 100') == ('degrees()', 'setheading(0)', 'forward(100)', 'radians()') 

990 assert get_turtle_code('w 100') == ('degrees()', 'setheading(180)', 'forward(100)', 'radians()') 

991 assert get_turtle_code('nw 100') == ('degrees()', 'setheading(135)', 'forward(100)', 'radians()') 

992 assert get_turtle_code('ne 100') == ('degrees()', 'setheading(45)', 'forward(100)', 'radians()') 

993 assert get_turtle_code('sw 100') == ('degrees()', 'setheading(225)', 'forward(100)', 'radians()') 

994 assert get_turtle_code('se 100') == ('degrees()', 'setheading(315)', 'forward(100)', 'radians()') 

995 

996 degrees() 

997 

998 

999 

1000 

1001 

1002 

1003 

1004# EXAMPLE PROGRAMS: 

1005 

1006def test_colorful_squares(): 

1007 sc('t 1000 0, ps 4') 

1008 

1009 for i in range(100): # Draw 100 squares. 

1010 # Move to a random place: 

1011 sc(f'pu,g {randint(-400, 200)} {randint(-400, 200)},pd,fc {random()} {random()} {random()}, pc {random()} {random()} {random()}') 

1012 line_length = randint(20, 200) 

1013 

1014 # Draw the filled-in square: 

1015 sc('bf') 

1016 for j in range(4): 

1017 sc(f'f {line_length}, l 90') 

1018 sc('ef') 

1019 

1020 sc('u') 

1021 sc('reset') 

1022 

1023 

1024def test_draw_circles(): 

1025 # Draw circle in the top half of the window: 

1026 sc('sh 0') # Face right. 

1027 for i in range(20): 

1028 sc(f'cir {i * 10}') 

1029 

1030 # Draw circles in the bottom half of the window: 

1031 sc('sh 180') # Face left. 

1032 for i in range(20): 

1033 sc(f'cir {i * 10}') 

1034 sc('u') 

1035 sc('reset') 

1036 

1037 

1038def test_curve_path_filled(): 

1039 for i in range(50): 

1040 sc(f'fc {random()} {random()} {random()}') 

1041 

1042 # Set a random heading and draw several short lines with changing direction: 

1043 sc(f'sh {randint(0, 360)}, bf') 

1044 

1045 for j in range(randint(200, 600)): 

1046 sc(f'f 1,l {randint(-4, 4)}') 

1047 sc(f'h, ef') 

1048 sc('u') 

1049 sc('reset') 

1050 

1051 

1052if __name__ == '__main__': 

1053 pytest.main()