Initial commit: TDD Workshop exercises for participants
- Password Validator kata with starter code and tests - Shopping Cart kata with starter code and tests - FizzBuzz reference code (from live demo) - Setup guide and TDD reference card - No solutions included (participants implement themselves)
This commit is contained in:
commit
3d94c96ed2
13 changed files with 1469 additions and 0 deletions
157
password_validator/test/password_validator_test.dart
Normal file
157
password_validator/test/password_validator_test.dart
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
import 'package:test/test.dart';
|
||||
import '../lib/password_validator.dart';
|
||||
|
||||
// ============================================================
|
||||
// PASSWORD VALIDATOR — Workshop Starter
|
||||
// Follow Red → Green → Refactor strictly.
|
||||
// Uncomment one test at a time. Make it pass. Then the next.
|
||||
// ============================================================
|
||||
|
||||
void main() {
|
||||
late PasswordValidator validator;
|
||||
|
||||
setUp(() {
|
||||
validator = PasswordValidator();
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// STEP 1 — Minimum length
|
||||
// A password needs at least 8 characters.
|
||||
// Start here. Everything else builds on a valid-length string.
|
||||
// ──────────────────────────────────────────────────────────
|
||||
group('Minimum length (8 characters)', () {
|
||||
test('rejects a password shorter than 8 characters', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab1!xyz');
|
||||
// expect(result.isValid, isFalse);
|
||||
// expect(result.errors, contains('Must be at least 8 characters long'));
|
||||
});
|
||||
|
||||
test('accepts a password that is exactly 8 characters', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab1!xyzw');
|
||||
// expect(result.isValid, isTrue); // assuming other rules pass too
|
||||
});
|
||||
|
||||
test('accepts a password longer than 8 characters', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab1!xyzwqr');
|
||||
// expect(result.isValid, isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// STEP 2 — Uppercase letter
|
||||
// At least one A–Z character must be present.
|
||||
// ──────────────────────────────────────────────────────────
|
||||
group('Uppercase letter required', () {
|
||||
test('rejects a password with no uppercase letters', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('ab1!xyzw');
|
||||
// expect(result.isValid, isFalse);
|
||||
// expect(result.errors, contains('Must contain at least one uppercase letter'));
|
||||
});
|
||||
|
||||
test('accepts a password with at least one uppercase letter', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab1!xyzw');
|
||||
// expect(result.isValid, isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// STEP 3 — Digit required
|
||||
// At least one 0–9 character must be present.
|
||||
// ──────────────────────────────────────────────────────────
|
||||
group('Digit required', () {
|
||||
test('rejects a password with no digits', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab!!xyzw');
|
||||
// expect(result.isValid, isFalse);
|
||||
// expect(result.errors, contains('Must contain at least one digit'));
|
||||
});
|
||||
|
||||
test('accepts a password with at least one digit', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab1!xyzw');
|
||||
// expect(result.isValid, isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// STEP 4 — Special character required
|
||||
// At least one of: ! @ # $ % ^ & *
|
||||
// ──────────────────────────────────────────────────────────
|
||||
group('Special character required', () {
|
||||
test('rejects a password with no special characters', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab1xxxyw');
|
||||
// expect(result.isValid, isFalse);
|
||||
// expect(result.errors, contains('Must contain at least one special character (!@#\$%^&*)'));
|
||||
});
|
||||
|
||||
test('accepts a password with at least one special character', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab1!xyzw');
|
||||
// expect(result.isValid, isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// STEP 5 — No spaces allowed
|
||||
// ──────────────────────────────────────────────────────────
|
||||
group('No spaces allowed', () {
|
||||
test('rejects a password that contains a space', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab1! xyz');
|
||||
// expect(result.isValid, isFalse);
|
||||
// expect(result.errors, contains('Must not contain spaces'));
|
||||
});
|
||||
|
||||
test('accepts a password with no spaces', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Ab1!xyzw');
|
||||
// expect(result.isValid, isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// STEP 6 — Multiple errors reported at once
|
||||
// The validator collects ALL failures, not just the first.
|
||||
// This is the refactor insight: rules should be independent.
|
||||
// ──────────────────────────────────────────────────────────
|
||||
group('Multiple errors reported together', () {
|
||||
test('reports all failures for a completely invalid password', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('bad');
|
||||
// expect(result.isValid, isFalse);
|
||||
// expect(result.errors.length, equals(4)); // length, uppercase, digit, special char
|
||||
});
|
||||
|
||||
test('a fully valid password has no errors', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('MyP@ssw0rd');
|
||||
// expect(result.isValid, isTrue);
|
||||
// expect(result.errors, isEmpty);
|
||||
});
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// BONUS — Edge cases (if you finish early)
|
||||
// ──────────────────────────────────────────────────────────
|
||||
group('Edge cases', () {
|
||||
test('empty string is invalid and reports the length error', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('');
|
||||
// expect(result.isValid, isFalse);
|
||||
// expect(result.errors, contains('Must be at least 8 characters long'));
|
||||
});
|
||||
|
||||
test('exactly the minimum: 8 chars, all rules satisfied', () {
|
||||
// TODO: uncomment when ready
|
||||
// final result = validator.validate('Aa1!aaaa');
|
||||
// expect(result.isValid, isTrue);
|
||||
// expect(result.errors, isEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue