Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
huffman_btreepic_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
38#include <gtest/gtest.h>
39#include <sstream>
40#include <Huffman.H>
41#include <huffman_btreepic.H>
42
43using namespace std;
44
45// =============================================================================
46// Test Fixtures
47// =============================================================================
48
49class HuffmanBtreepicTest : public ::testing::Test
50{
51protected:
52 void SetUp() override
53 {
55 output_ptr = nullptr;
56 }
57
58 void TearDown() override
59 {
61 output_ptr = nullptr;
62 }
63
64 // Helper to create a simple Huffman tree from a string
66 {
68 char * str = const_cast<char*>(text.c_str());
69 encoder.read_input(str, true);
70 return encoder;
71 }
72};
73
74// =============================================================================
75// Infix_Desc Tests
76// =============================================================================
77
85
93
94// =============================================================================
95// Level_Desc Tests
96// =============================================================================
97
104
106{
107 Freq_Node node;
108 Level_Desc desc(true, &node);
109 EXPECT_TRUE(desc.is_left);
110 EXPECT_EQ(desc.level_succ, &node);
111}
112
113// =============================================================================
114// Offset Enum Tests
115// =============================================================================
116
123
124// =============================================================================
125// get_offset Tests
126// =============================================================================
127
135
137{
138 // Indices beyond MAX_OFFSET_INDEX should be clamped
141 EXPECT_DOUBLE_EQ(get_offset(1000), 90);
142}
143
144// =============================================================================
145// num_digits Tests
146// =============================================================================
147
154
162
163// =============================================================================
164// reset_huffman_btreepic_state Tests
165// =============================================================================
166
168{
169 // Add something to the infix table
170 Freq_Node node;
171 node.get_key().first = "a";
172 node.get_key().second = 5;
173 infix_table.insert(&node, Infix_Desc(1, 2));
174 EXPECT_EQ(infix_table.size(), 1u);
175
177 EXPECT_EQ(infix_table.size(), 0u);
178}
179
189
191{
192 Freq_Node node;
193 pred = &node;
194 EXPECT_NE(pred, nullptr);
195
197 EXPECT_EQ(pred, nullptr);
198}
199
200// =============================================================================
201// huffman_to_btreepic Basic Tests
202// =============================================================================
203
205{
206 stringstream ss;
207 output_ptr = &ss;
208 huffman_to_btreepic(nullptr, false);
209 EXPECT_TRUE(ss.str().empty());
210}
211
213{
214 Freq_Node node;
215 node.get_key().first = "a";
216 node.get_key().second = 1;
217 LLINK(&node) = nullptr;
218 RLINK(&node) = nullptr;
219
220 output_ptr = nullptr;
221 // Should not crash
223}
224
226{
227 Freq_Node node;
228 node.get_key().first = "a";
229 node.get_key().second = 5;
230 LLINK(&node) = nullptr;
231 RLINK(&node) = nullptr;
232
233 stringstream ss;
234 output_ptr = &ss;
235 huffman_to_btreepic(&node, false);
236
237 string output = ss.str();
238 EXPECT_TRUE(output.find("start-prefix") != string::npos);
239 EXPECT_TRUE(output.find("start-key") != string::npos);
240 EXPECT_TRUE(output.find("\"5\"") != string::npos);
241 EXPECT_TRUE(output.find("TAG 0") != string::npos);
242}
243
245{
246 Freq_Node node;
247 node.get_key().first = "a";
248 node.get_key().second = 5;
249 LLINK(&node) = nullptr;
250 RLINK(&node) = nullptr;
251
252 stringstream ss;
253 huffman_to_btreepic(&node, ss, false);
254
255 string output = ss.str();
256 EXPECT_TRUE(output.find("start-prefix") != string::npos);
257 EXPECT_TRUE(output.find("start-key") != string::npos);
258}
259
260// =============================================================================
261// LaTeX Character Escaping Tests
262// =============================================================================
263
265{
266 Freq_Node node;
267 node.get_key().first = "\n";
268 node.get_key().second = 1;
269 LLINK(&node) = nullptr;
270 RLINK(&node) = nullptr;
271
272 stringstream ss;
273 output_ptr = &ss;
274 huffman_to_btreepic(&node, false);
275
276 EXPECT_TRUE(ss.str().find("$\\backslash$n") != string::npos);
277}
278
280{
281 Freq_Node node;
282 node.get_key().first = "$";
283 node.get_key().second = 1;
284 LLINK(&node) = nullptr;
285 RLINK(&node) = nullptr;
286
287 stringstream ss;
288 output_ptr = &ss;
289 huffman_to_btreepic(&node, false);
290
291 EXPECT_TRUE(ss.str().find("\\$") != string::npos);
292}
293
295{
296 Freq_Node node;
297 node.get_key().first = "&";
298 node.get_key().second = 1;
299 LLINK(&node) = nullptr;
300 RLINK(&node) = nullptr;
301
302 stringstream ss;
303 output_ptr = &ss;
304 huffman_to_btreepic(&node, false);
305
306 EXPECT_TRUE(ss.str().find("\\&") != string::npos);
307}
308
310{
311 Freq_Node node;
312 node.get_key().first = "#";
313 node.get_key().second = 1;
314 LLINK(&node) = nullptr;
315 RLINK(&node) = nullptr;
316
317 stringstream ss;
318 output_ptr = &ss;
319 huffman_to_btreepic(&node, false);
320
321 EXPECT_TRUE(ss.str().find("\\#") != string::npos);
322}
323
325{
326 Freq_Node node;
327 node.get_key().first = "%";
328 node.get_key().second = 1;
329 LLINK(&node) = nullptr;
330 RLINK(&node) = nullptr;
331
332 stringstream ss;
333 output_ptr = &ss;
334 huffman_to_btreepic(&node, false);
335
336 EXPECT_TRUE(ss.str().find("\\%") != string::npos);
337}
338
340{
341 Freq_Node node;
342 node.get_key().first = " ";
343 node.get_key().second = 1;
344 LLINK(&node) = nullptr;
345 RLINK(&node) = nullptr;
346
347 stringstream ss;
348 output_ptr = &ss;
349 huffman_to_btreepic(&node, false);
350
351 EXPECT_TRUE(ss.str().find("$\\square$") != string::npos);
352}
353
355{
356 Freq_Node node;
357 node.get_key().first = "\\";
358 node.get_key().second = 1;
359 LLINK(&node) = nullptr;
360 RLINK(&node) = nullptr;
361
362 stringstream ss;
363 output_ptr = &ss;
364 huffman_to_btreepic(&node, false);
365
366 EXPECT_TRUE(ss.str().find("$\\backslash$") != string::npos);
367}
368
370{
371 Freq_Node node;
372 node.get_key().first = "\"";
373 node.get_key().second = 1;
374 LLINK(&node) = nullptr;
375 RLINK(&node) = nullptr;
376
377 stringstream ss;
378 output_ptr = &ss;
379 huffman_to_btreepic(&node, false);
380
381 EXPECT_TRUE(ss.str().find("$\\prime\\prime$") != string::npos);
382}
383
385{
386 Freq_Node node;
387 node.get_key().first = "";
388 node.get_key().second = 1;
389 LLINK(&node) = nullptr;
390 RLINK(&node) = nullptr;
391
392 stringstream ss;
393 output_ptr = &ss;
394 huffman_to_btreepic(&node, false);
395
396 EXPECT_TRUE(ss.str().find("$\\neg$") != string::npos);
397}
398
400{
402 node1.get_key().first = "{";
403 node1.get_key().second = 1;
404 node2.get_key().first = "}";
405 node2.get_key().second = 1;
406 LLINK(&node1) = nullptr;
407 RLINK(&node1) = nullptr;
408 LLINK(&node2) = nullptr;
409 RLINK(&node2) = nullptr;
410
411 stringstream ss1, ss2;
412 output_ptr = &ss1;
413 huffman_to_btreepic(&node1, false);
414 output_ptr = &ss2;
415 huffman_to_btreepic(&node2, false);
416
417 EXPECT_TRUE(ss1.str().find("$\\{$") != string::npos);
418 EXPECT_TRUE(ss2.str().find("$\\}$") != string::npos);
419}
420
421// =============================================================================
422// Full Huffman Tree Tests
423// =============================================================================
424
426{
427 Huffman_Encoder_Engine encoder = create_encoder("aab");
428 Freq_Node * root = encoder.get_freq_root();
429
430 stringstream ss;
431 output_ptr = &ss;
433
434 string output = ss.str();
435
436 // Should have start-prefix line
437 EXPECT_TRUE(output.find("start-prefix") != string::npos);
438
439 // Should have start-key line
440 EXPECT_TRUE(output.find("start-key") != string::npos);
441
442 // Should have TAG commands for leaves
443 EXPECT_TRUE(output.find("TAG") != string::npos);
444
445 // Clean up
446 destroyRec(encoder.get_root());
447 destroyRec(encoder.get_freq_root());
448}
449
451{
452 Huffman_Encoder_Engine encoder = create_encoder("abcdefgh");
453 Freq_Node * root = encoder.get_freq_root();
454
455 stringstream ss;
456 output_ptr = &ss;
458
459 string output = ss.str();
460
461 // Should have all the standard elements
462 EXPECT_TRUE(output.find("start-prefix") != string::npos);
463 EXPECT_TRUE(output.find("start-key") != string::npos);
464
465 // Clean up
466 destroyRec(encoder.get_root());
467 destroyRec(encoder.get_freq_root());
468}
469
471{
472 Huffman_Encoder_Engine encoder1 = create_encoder("aab");
473 Huffman_Encoder_Engine encoder2 = create_encoder("xyz");
474
475 stringstream ss1, ss2;
476
477 output_ptr = &ss1;
478 huffman_to_btreepic(encoder1.get_freq_root(), false);
479
480 output_ptr = &ss2;
481 huffman_to_btreepic(encoder2.get_freq_root(), false);
482
483 // Both outputs should be valid and independent
484 EXPECT_TRUE(ss1.str().find("start-prefix") != string::npos);
485 EXPECT_TRUE(ss2.str().find("start-prefix") != string::npos);
486
487 // They should be different
488 EXPECT_NE(ss1.str(), ss2.str());
489
490 // Clean up
491 destroyRec(encoder1.get_root());
492 destroyRec(encoder1.get_freq_root());
493 destroyRec(encoder2.get_root());
494 destroyRec(encoder2.get_freq_root());
495}
496
497// =============================================================================
498// Output Format Tests
499// =============================================================================
500
502{
503 Huffman_Encoder_Engine encoder = create_encoder("abc");
504 Freq_Node * root = encoder.get_freq_root();
505
506 stringstream ss;
507 output_ptr = &ss;
509
510 string output = ss.str();
511 EXPECT_EQ(output.substr(0, 12), "start-prefix");
512
513 destroyRec(encoder.get_root());
514 destroyRec(encoder.get_freq_root());
515}
516
518{
519 Huffman_Encoder_Engine encoder = create_encoder("abc");
520 Freq_Node * root = encoder.get_freq_root();
521
522 stringstream ss;
523 output_ptr = &ss;
525
526 string output = ss.str();
527 EXPECT_TRUE(output.find("\nstart-key ") != string::npos);
528
529 destroyRec(encoder.get_root());
530 destroyRec(encoder.get_freq_root());
531}
532
534{
535 Freq_Node node;
536 node.get_key().first = "x";
537 node.get_key().second = 7;
538 LLINK(&node) = nullptr;
539 RLINK(&node) = nullptr;
540
541 stringstream ss;
542 output_ptr = &ss;
543 huffman_to_btreepic(&node, false);
544
545 string output = ss.str();
546 // TAG format: TAG <pos> "<symbol>" S 0 -20
547 EXPECT_TRUE(output.find("TAG 0 \"x\" S 0 -20") != string::npos);
548}
549
550// =============================================================================
551// minimal_gap Tests
552// =============================================================================
553
558
566
567// =============================================================================
568// Binary Tree Structure Tests
569// =============================================================================
570
572{
573 /*
574 * Create a simple 3-node tree:
575 * root (3)
576 * / \
577 * left(1) right(2)
578 */
579 Freq_Node root, left, right;
580
581 root.get_key().first = "";
582 root.get_key().second = 3;
583 left.get_key().first = "a";
584 left.get_key().second = 1;
585 right.get_key().first = "b";
586 right.get_key().second = 2;
587
588 LLINK(&root) = &left;
589 RLINK(&root) = &right;
590 LLINK(&left) = nullptr;
591 RLINK(&left) = nullptr;
592 LLINK(&right) = nullptr;
593 RLINK(&right) = nullptr;
594
595 stringstream ss;
596 output_ptr = &ss;
597 huffman_to_btreepic(&root, false);
598
599 string output = ss.str();
600
601 // Should have TAGs for both leaves
602 EXPECT_TRUE(output.find("TAG") != string::npos);
603 EXPECT_TRUE(output.find("\"a\"") != string::npos);
604 EXPECT_TRUE(output.find("\"b\"") != string::npos);
605}
606
607// =============================================================================
608// Backward Compatibility Tests
609// =============================================================================
610
612{
613 // These should compile and be accessible
616 EXPECT_EQ(&pred, &pred);
618}
619
621{
622 Freq_Node node;
623 node.get_key().first = "a";
624 node.get_key().second = 1;
625 LLINK(&node) = nullptr;
626 RLINK(&node) = nullptr;
627
628 stringstream ss;
629 output_ptr = &ss; // Legacy: set global output pointer
630
631 // Legacy API call
632 huffman_to_btreepic(&node);
633
634 EXPECT_FALSE(ss.str().empty());
635}
636
637// =============================================================================
638// Edge Cases
639// =============================================================================
640
642{
643 Freq_Node node;
644 node.get_key().first = "verylongsymbolname";
645 node.get_key().second = 1;
646 LLINK(&node) = nullptr;
647 RLINK(&node) = nullptr;
648
649 stringstream ss;
650 output_ptr = &ss;
651
652 // Should not crash due to offset array bounds
654}
655
657{
658 Freq_Node node;
659 node.get_key().first = "a";
660 node.get_key().second = 0;
661 LLINK(&node) = nullptr;
662 RLINK(&node) = nullptr;
663
664 stringstream ss;
665 output_ptr = &ss;
666 huffman_to_btreepic(&node, false);
667
668 EXPECT_TRUE(ss.str().find("\"0\"") != string::npos);
669}
670
672{
673 Freq_Node node;
674 node.get_key().first = "a";
675 node.get_key().second = 1000000;
676 LLINK(&node) = nullptr;
677 RLINK(&node) = nullptr;
678
679 stringstream ss;
680 output_ptr = &ss;
681 huffman_to_btreepic(&node, false);
682
683 EXPECT_TRUE(ss.str().find("\"1000000\"") != string::npos);
684}
685
686// =============================================================================
687// Integration Test with Real Huffman Encoding
688// =============================================================================
689
691{
692 const char * text = "hello world";
694 char * str = const_cast<char*>(text);
695 encoder.read_input(str, true);
696
697 stringstream ss;
698 huffman_to_btreepic(encoder.get_freq_root(), ss, false);
699
700 string output = ss.str();
701
702 // Verify output structure
703 EXPECT_TRUE(output.find("start-prefix") != string::npos);
704 EXPECT_TRUE(output.find("start-key") != string::npos);
705
706 // Should have TAGs for leaf nodes
707 size_t tag_count = 0;
708 size_t pos = 0;
709 while ((pos = output.find("TAG", pos)) != string::npos)
710 {
711 tag_count++;
712 pos += 3;
713 }
714
715 // "hello world" has unique chars: h, e, l, o, ' ', w, r, d
716 // But l appears 3 times, o 2 times, so we have fewer unique symbols
717 EXPECT_GE(tag_count, 1u);
718
719 // Clean up
720 destroyRec(encoder.get_root());
721 destroyRec(encoder.get_freq_root());
722}
723
724int main(int argc, char **argv)
725{
726 ::testing::InitGoogleTest(&argc, argv);
727 return RUN_ALL_TESTS();
728}
Huffman coding for data compression.
int main()
@ LEFT
Definition btreepic.C:171
@ RIGHT
Definition btreepic.C:171
Node for binary search tree.
Key & get_key() noexcept
void empty() noexcept
empty the list
Definition htlist.H:1689
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair.
const size_t & size() const
Returns the cardinality of the set.
Huffman_Encoder_Engine create_encoder(const string &text)
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4060
constexpr Node *& RLINK(Node *p) noexcept
Return the right tree of p.
void destroyRec(Node *&root) noexcept
Free recursively all the memory occupied by the tree root
constexpr Node *& LLINK(Node *p) noexcept
Return a pointer to left subtree.
Huffman tree visualization for btreepic LaTeX package.
void reset_huffman_btreepic_state() noexcept
Reset global state for a new tree processing.
Freq_Node * pred
Predecessor node in level-order traversal.
long double get_offset(size_t index) noexcept
Get safe offset value with bounds checking.
@ NO_OFFSET
No offset applied.
size_t num_digits(const int &n)
Compute number of decimal digits in an integer.
DynMapTree< Freq_Node *, Infix_Desc, Treap > infix_table
Map from node pointer to infix position descriptor.
int minimal_gap
Minimum gap (in nodes) before applying offset adjustment.
void huffman_to_btreepic(Freq_Node *p, const bool with_level_adjust=false)
Generate btreepic specification for a Huffman tree.
std::ostream * output_ptr
Output stream pointer for btreepic commands.
Level_Table level_table
Map from node pointer to level traversal descriptor.
TEST_F(HuffmanBtreepicTest, InfixDescDefaultConstruction)
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Descriptor for infix (in-order) traversal position.
Descriptor for level-order traversal information.
ofstream output
Definition writeHeap.C:213