feat: add new tests
This commit is contained in:
@@ -1,8 +1,4 @@
|
|||||||
/// Support for doing something awesome.
|
|
||||||
///
|
|
||||||
/// More dartdocs go here.
|
|
||||||
library;
|
library;
|
||||||
|
|
||||||
export 'src/potato_pass_core_base.dart';
|
// Экспортируем наш 6-битный кодировщик
|
||||||
|
export 'src/encoding/compact_text_encoder.dart';
|
||||||
// TODO: Export any libraries intended for clients of this package.
|
|
||||||
79
lib/src/encoding/compact_text_encoder.dart
Normal file
79
lib/src/encoding/compact_text_encoder.dart
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
/// Класс для упаковки/распаковки текста в 6-битный формат.
|
||||||
|
/// 4 символа упаковываются ровно в 3 байта (сжатие ~62% для кириллицы).
|
||||||
|
abstract class CompactTextEncoder {
|
||||||
|
/// Словарь из 64 символов (индексы от 0 до 63)
|
||||||
|
static const String charset = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯABCDEFGHIJKLMNOPQRSTUVWXYZ -.,_';
|
||||||
|
|
||||||
|
/// Упаковывает строку [text] в байтовый массив Uint8List.
|
||||||
|
static Uint8List encode(String text) {
|
||||||
|
if (text.isEmpty) {
|
||||||
|
return Uint8List(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String upperText = text.toUpperCase();
|
||||||
|
final List<int> indices = [];
|
||||||
|
|
||||||
|
// Преобразуем каждый символ в индекс от 0 до 63
|
||||||
|
for (int i = 0; i < upperText.length; i++) {
|
||||||
|
int idx = charset.indexOf(upperText[i]);
|
||||||
|
// Если символа нет в словаре, заменяем на пробел
|
||||||
|
if (idx == -1) {
|
||||||
|
idx = charset.indexOf(' ');
|
||||||
|
}
|
||||||
|
indices.add(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добиваем длину до кратности 4 символам (символом '_')
|
||||||
|
while (indices.length % 4 != 0) {
|
||||||
|
indices.add(charset.indexOf('_'));
|
||||||
|
}
|
||||||
|
|
||||||
|
final int byteLength = (indices.length ~/ 4) * 3;
|
||||||
|
final Uint8List result = Uint8List(byteLength);
|
||||||
|
|
||||||
|
int byteIdx = 0;
|
||||||
|
for (int i = 0; i < indices.length; i += 4) {
|
||||||
|
int c1 = indices[i];
|
||||||
|
int c2 = indices[i + 1];
|
||||||
|
int c3 = indices[i + 2];
|
||||||
|
int c4 = indices[i + 3];
|
||||||
|
|
||||||
|
// Упаковка 4 x 6 бит (24 бита) в 3 байта по 8 бит
|
||||||
|
result[byteIdx++] = (c1 << 2) | (c2 >> 4);
|
||||||
|
result[byteIdx++] = ((c2 & 0x0F) << 4) | (c3 >> 2);
|
||||||
|
result[byteIdx++] = ((c3 & 0x03) << 6) | c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Распаковывает байтовый массив обратно в строку.
|
||||||
|
static String decode(Uint8List bytes) {
|
||||||
|
if (bytes.isEmpty) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuffer sb = StringBuffer();
|
||||||
|
|
||||||
|
for (int i = 0; i < bytes.length; i += 3) {
|
||||||
|
int b1 = bytes[i];
|
||||||
|
int b2 = bytes[i + 1];
|
||||||
|
int b3 = bytes[i + 2];
|
||||||
|
|
||||||
|
int c1 = (b1 >> 2) & 0x3F;
|
||||||
|
int c2 = ((b1 & 0x03) << 4) | ((b2 >> 4) & 0x0F);
|
||||||
|
int c3 = ((b2 & 0x0F) << 2) | ((b3 >> 6) & 0x03);
|
||||||
|
int c4 = b3 & 0x3F;
|
||||||
|
|
||||||
|
sb.write(charset[c1]);
|
||||||
|
sb.write(charset[c2]);
|
||||||
|
sb.write(charset[c3]);
|
||||||
|
sb.write(charset[c4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Удаляем заполнители и пробелы по краям
|
||||||
|
return sb.toString().replaceAll('_', '').trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,53 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
import 'package:potato_pass_core/potato_pass_core.dart';
|
import 'package:potato_pass_core/potato_pass_core.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('A group of tests', () {
|
group('CompactTextEncoder Tests', () {
|
||||||
final awesome = Awesome();
|
test('Кодирование и декодирование русской строки', () {
|
||||||
|
const input = 'ИВАНОВ ИВАН ИВАНОВИЧ';
|
||||||
|
|
||||||
|
// Кодируем
|
||||||
|
final Uint8List encoded = CompactTextEncoder.encode(input);
|
||||||
|
|
||||||
|
// Проверяем декодирование
|
||||||
|
final String decoded = CompactTextEncoder.decode(encoded);
|
||||||
|
|
||||||
setUp(() {
|
expect(decoded, equals(input));
|
||||||
// Additional setup goes here.
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('First Test', () {
|
test('Проверка сжатия размера', () {
|
||||||
expect(awesome.isAwesome, isTrue);
|
const input = 'ИВАНОВ ИВАН'; // 11 символов
|
||||||
|
|
||||||
|
// В UTF-8 кириллица весит 2 байта на символ и займут 22 байта
|
||||||
|
// В 6-битном кодировщике 11 символов округляются до 12 и займут 9 байт
|
||||||
|
final Uint8List encoded = CompactTextEncoder.encode(input);
|
||||||
|
|
||||||
|
expect(encoded.length, equals(9));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Обработка строчных букв (автоперевод в верхний регистр)', () {
|
||||||
|
const input = 'Петров Петр';
|
||||||
|
final Uint8List encoded = CompactTextEncoder.encode(input);
|
||||||
|
final String decoded = CompactTextEncoder.decode(encoded);
|
||||||
|
|
||||||
|
expect(decoded, equals('ПЕТРОВ ПЕТР'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Тест некодируемых символов', () {
|
||||||
|
const input = '_.`~!@#\$%^&*()=+\\||//1234567890.';//2 точки и 29 некодирукемый символ (точки чтобы не обрезало) и _ в начале которе
|
||||||
|
final Uint8List encoded = CompactTextEncoder.encode(input);
|
||||||
|
final String decoded = CompactTextEncoder.decode(encoded);
|
||||||
|
|
||||||
|
expect(decoded, equals('. .'));//2 точки и 29 пробелов (некодируемые символы заменяются на пробелы)
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Тест кодируемости всех символов', () {
|
||||||
|
const input = 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯABCDEFGHIJKLMNOPQRSTUVWXYZ .-,';//Все неслужебные символы
|
||||||
|
final Uint8List encoded = CompactTextEncoder.encode(input);
|
||||||
|
final String decoded = CompactTextEncoder.decode(encoded);
|
||||||
|
|
||||||
|
expect(decoded, equals('АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯABCDEFGHIJKLMNOPQRSTUVWXYZ .-,'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user