@@ -302,3 +302,166 @@ TEST(SNLTruthTableTreeEvalTest, NullChildNodeThrowsViaIdMismatch) {
302302 // Now nodeFromId(childId) will return null (id mismatch), so eval should throw "Null child node"
303303 EXPECT_THROW (parent->eval ({true }), std::logic_error);
304304}
305+
306+ TEST (SNLTruthTableTreeApi_Additions, AllocateNodeAndEvalInput) {
307+ SNLTruthTableTree tree;
308+
309+ // The idx constructor currently yields a table-like node in this implementation.
310+ // Assert that evaluating it without wiring children throws the expected logic_error.
311+ auto node = std::make_shared<Node>(0u , &tree);
312+
313+ // Defensive: try to mark as Input (harmless) but do not rely on it.
314+ node->type = Node::Type::Input;
315+ node->data .inputIndex = 0 ;
316+ node->truthTable = SNLTruthTable (); // attempt to clear arity
317+
318+ uint32_t id = tree.allocateNode (node);
319+ EXPECT_EQ (tree.nodeFromId (id).get (), node.get ());
320+
321+ // Implementation treats this as a table node; evaluating without children should throw.
322+ EXPECT_THROW (node->eval ({true }), std::logic_error);
323+ }
324+
325+
326+ TEST (SNLTruthTableTreeApi_Additions, AllocateNullSharedPtrThrows) {
327+ SNLTruthTableTree tree;
328+ std::shared_ptr<Node> nullsp;
329+ EXPECT_THROW (tree.allocateNode (nullsp), std::logic_error);
330+ }
331+
332+ TEST (SNLTruthTableTreeApi_Additions, NodeFromId_NodeIdMismatch) {
333+ SNLTruthTableTree tree;
334+
335+ auto node = std::make_shared<Node>(0u , &tree);
336+ node->type = Node::Type::Input;
337+ node->data .inputIndex = 0 ;
338+ node->truthTable = SNLTruthTable ();
339+ uint32_t id = tree.allocateNode (node);
340+
341+ EXPECT_EQ (tree.nodeFromId (id).get (), node.get ());
342+
343+ // Corrupt nodeID to force nodeFromId to return null
344+ node->nodeID = SNLTruthTableTree::kInvalidId ;
345+ EXPECT_EQ (tree.nodeFromId (id).get (), nullptr );
346+ }
347+
348+ TEST (SNLTruthTableTreeEval_Additions, TableNodeChildrenCountMismatchThrows) {
349+ SNLTruthTableTree tree;
350+
351+ auto tableNode = std::make_shared<Node>(0u , &tree);
352+ tableNode->type = Node::Type::Table;
353+ tableNode->truthTable = makeMaskTable (1 , 0b01 ); // arity 1
354+ tree.allocateNode (tableNode);
355+
356+ EXPECT_THROW (tableNode->eval ({true }), std::logic_error);
357+ }
358+
359+ TEST (SNLTruthTableTreeEval_Additions, InvalidChildIdThrows) {
360+ SNLTruthTableTree tree;
361+
362+ auto parent = std::make_shared<Node>(0u , &tree);
363+ parent->type = Node::Type::Table;
364+ parent->truthTable = makeMaskTable (1 , 0b01 );
365+ parent->childrenIds .push_back (SNLTruthTableTree::kInvalidId );
366+
367+ tree.allocateNode (parent);
368+ EXPECT_THROW (parent->eval ({true }), std::logic_error);
369+ }
370+
371+ TEST (SNLTruthTableTreeEval_Additions, NullChildNodeThrowsViaIdMismatch) {
372+ SNLTruthTableTree tree;
373+
374+ auto child = std::make_shared<Node>(0u , &tree);
375+ child->type = Node::Type::Input;
376+ child->data .inputIndex = 0 ;
377+ child->truthTable = SNLTruthTable ();
378+ uint32_t childId = tree.allocateNode (child);
379+
380+ EXPECT_EQ (tree.nodeFromId (childId).get (), child.get ());
381+
382+ // Corrupt stored nodeID so nodeFromId returns null
383+ child->nodeID = SNLTruthTableTree::kInvalidId ;
384+
385+ auto parent = std::make_shared<Node>(0u , &tree);
386+ parent->type = Node::Type::Table;
387+ parent->truthTable = makeMaskTable (1 , 0b01 );
388+ parent->childrenIds .push_back (childId);
389+ tree.allocateNode (parent);
390+
391+ EXPECT_THROW (parent->eval ({true }), std::logic_error);
392+ }
393+
394+ TEST (SNLTruthTableTreeEval_Additions, InputChildIndexOutOfRangeThrows) {
395+ SNLTruthTableTree tree;
396+
397+ auto child = std::make_shared<Node>(0u , &tree);
398+ child->type = Node::Type::Input;
399+ child->data .inputIndex = 5 ; // out of range
400+ child->truthTable = SNLTruthTable ();
401+ uint32_t childId = tree.allocateNode (child);
402+
403+ auto parent = std::make_shared<Node>(0u , &tree);
404+ parent->type = Node::Type::Table;
405+ parent->truthTable = makeMaskTable (1 , 0b01 );
406+ parent->childrenIds .push_back (childId);
407+ tree.allocateNode (parent);
408+
409+ EXPECT_THROW (parent->eval ({true , false }), std::out_of_range);
410+ EXPECT_THROW (parent->eval ({}), std::out_of_range);
411+ }
412+
413+ TEST (SNLTruthTableTreeEval_Additions, EvaluatesInputChildAndReadsTableBit) {
414+ SNLTruthTableTree tree;
415+
416+ auto child = std::make_shared<Node>(0u , &tree);
417+ child->type = Node::Type::Input;
418+ child->data .inputIndex = 0 ;
419+ child->truthTable = SNLTruthTable ();
420+ uint32_t childId = tree.allocateNode (child);
421+
422+ auto parent = std::make_shared<Node>(0u , &tree);
423+ parent->type = Node::Type::Table;
424+ parent->truthTable = makeMaskTable (1 , 0b01 ); // bit0=true, bit1=false
425+ parent->childrenIds .push_back (childId);
426+ tree.allocateNode (parent);
427+
428+ EXPECT_TRUE (parent->eval ({false }));
429+ EXPECT_FALSE (parent->eval ({true }));
430+ }
431+
432+ TEST (SNLTruthTableTreeAddChild_Additions, AddChildIdRejectsInvalidId) {
433+ SNLTruthTableTree tree;
434+
435+ auto parent = std::make_shared<Node>(0u , &tree);
436+ parent->type = Node::Type::Table;
437+ parent->truthTable = makeMaskTable (0 , 0 );
438+ tree.allocateNode (parent);
439+
440+ EXPECT_THROW (parent->addChildId (SNLTruthTableTree::kInvalidId ), std::logic_error);
441+ }
442+
443+ TEST (SNLTruthTableTreeAddChild_Additions, AddChildIdEstablishesParentChildRelation) {
444+ SNLTruthTableTree tree;
445+
446+ auto parent = std::make_shared<Node>(0u , &tree);
447+ parent->type = Node::Type::Table;
448+ parent->truthTable = makeMaskTable (0 , 0 );
449+ uint32_t parentId = tree.allocateNode (parent);
450+
451+ auto child = std::make_shared<Node>(0u , &tree);
452+ child->type = Node::Type::Input;
453+ child->data .inputIndex = 0 ;
454+ child->truthTable = SNLTruthTable ();
455+ uint32_t childId = tree.allocateNode (child);
456+
457+ EXPECT_TRUE (parent->childrenIds .empty ());
458+ EXPECT_TRUE (child->parentIds .empty ());
459+
460+ EXPECT_NO_THROW (parent->addChildId (childId));
461+
462+ auto it = std::find (parent->childrenIds .begin (), parent->childrenIds .end (), childId);
463+ EXPECT_NE (it, parent->childrenIds .end ());
464+
465+ auto pit = std::find (child->parentIds .begin (), child->parentIds .end (), parentId);
466+ EXPECT_NE (pit, child->parentIds .end ());
467+ }
0 commit comments